Programmieren mit ARM64 Assembler

Aus C und Assembler mit Raspberry

Der ARM ist ein sogenannter RISC-Computer, was das Erlernen von Assembler theoretisch einfacher macht.

  • Wir verwenden Linux
  • Zahlen

-> Dezimal, Binär, Hexadezimal

  • CPU-Register

-> Ein 64-Bit-Programm auf einem ARM-Prozessor im Benutzermodus hat Zugriff auf 31 Allzweckregister, einen Programmzähler (PC) und eine Kombination aus Nullregister/Stapelzeiger

  • x0-x30
  • SP, XZR
  • x30, LR
  • PC
  • w0-w30, wzr: sind x-Register, die die unteren 32-Bit verwenden.

-> Zusätzliche Register Gleitkommaoperationen, Neon-Coprozessor, später

  • Aufbau von Data processing instructions:
 | 31   | 30     | 29                 | 28-24  | 23-22 | 21 | 20-16 | 15-10 | 9-5 | 4-0 |
 | Bits | Opcode | Set Condition Code | Opcode | Shift | 0  | Rm    | imm6  | Rn  | Rd  |

-> Erklärung

  • Memory

-> Instruktionen 32-Bit, Register 64-Bit, Memory-Adresssierung 64-Bit -> wie lösen.

  • Der GCC-Assembler

-> Maschinencode in lesbare Form -> Aufbau von Befehlen, Beispiel ldr, mov

  • Erstes Programm: Hello World
.global _start
_start: mov X0, #1
ldr X1, =helloworld
mov X2, #13
mov X8, #64
svc 0
mov X0, #0
mov X8, #93
svc 0
.data
helloworld: .ascii "Hello World!\n" 

as -o HelloWorld.o HelloWorld.s ld -o HelloWorld HelloWorld.o

  • Erklärung Code

-> Kommentare -> globales Symbol _start -> Assembler-Befehle: --> mov, ldr, svc 0 -> data

  • Linux-Systemaufrufe

-> Parameter in den Registern X0–X7 -> Rückgabe x0 -> Funktionsnummer in X8

  • Diassemblieren

-> objdump -s -d HellowWorld.o

Laden und Addieren

  • mov add
  • negative Zahlen

-> Beispiel: 5 + -3

 3 in 1 byte is 0x03 or 0000 0011.
 Inverting the bits is
 1111 1100
 Add 1 to get
 1111 1101 = 0xFD
 Now add
 5 + 0xFD = 0x102 = 2
  • Big vs. Little Endian

-> Reihenfolge der Bytes im Speicher -> ARM-Prozessor erlaubt beide Versionen -> Linux verwendet Little Endian

  • Shiften und Rotation
  • Carry-Flag

• Logical shift left • Logical shift right • Arithmetic shift right • Rotate right

  • Laden von Registern

-> mov x0,x1; Ein Alias. Gleiche ist möglich mit add x0, xzr, x1, aber tatsächlich ist es orr x0,xzr,x1 -> Verwendung von Aliase, um den Code besser zu verstehen, Problem beim debuggen, objdump, da eventuell andere Aliases verwendet werden.

  • mov

-> 1. MOVK XD, #imm16{, LSL #shift}

  2. MOV XD, #imm16{, LSL #shift}
  3. MOV XD, XS
  4. MOV XD, operand2
  5. MOVN XD, operand2
  • add/adc
  1. ADD{S} Xd, Xs, Operand2
  2. ADC{S} Xd, Xs, Operand2

Beispiel:

.global _start
_start: MOVN W0, #2
  ADD W0, W0, #1
  MOV X8, #93 // Service command code 93
  SVC 0

Rückgabe in w0 -> Kann mit "echo $?" ausgegeben werden.

  • Add with Carry

-> Übertrag. -> Beispiel:

 adds x1,x3,x5 //addiert untere 64-Bit
 adc  x0,x2,x4 //addiert obere 64-Bit mit Übertrag von zuvor
  • SUB/SBC

Tools

  • GNU MAKE

-> make -B: erstellt neue Kompilierungen

  • GDB
break (b) line Set breakpoint at line
run (r) Run the program
step (s) Single step program
continue (c) Continue running the program
quit (q or control-d) Exit gdb
control-c Interrupt the running program
info registers (i r) Print out the registers
info break Print out the breakpoints
delete n Delete breakpoint n
x /Nuf expression Show contents of memory
  • Gross-Compiling
  • Emulation



  • Interaktion mit anderen Programmiersprachen
  • Zugriff auf Hardwaregeräte
  • Anweisungen für den Gleitkommaprozessor
  • Anweisungen für den NEON-Prozessor