siiky
2023/05/04
2023/05/04
2023/05/12
video,course,programming
https://www.freecodecamp.org/news/learn-assembly-language-programming-with-arm/
https://invidious.snopyta.org/watch?v=gfmRrPjnEw4
Short-ish freecodecamp video about ARM assembly.
Registers R0 through R12, SP (Stack Pointer), LR (Link Register?), PC (Program Counter). R7 is used to specify syscalls. CPSR contains arithmetic flags (Negative, Carry, Zero, &c).
The different types of addressing:
Common instructions:
.global _start _start: MOV R0,=somedata // Save in R0 the address of somedata LDR R1,[R0] // Save in R1 the value stored at the address that's stored in R0 -- equivalent to R1 = *R0 LDR R2,[R0,#4] // Save in R2 the value stored at the address that's stored in R0, plus 4 bytes -- equivalent to R2 = *(R0+4) LDR R3,[R0,#4]! // Save in R2 the value stored at the address that's stored in R0, plus 4 bytes -- equivalent to R3 = *(++R0) (assume ++ increments 4 bytes) LDR R4,[R0],#4 // Save in R2 the value stored at the address that's stored in R0, plus 4 bytes -- equivalent to R4 = *(R0++) (assume ++ increments 4 bytes) MOV R7,#1 // 1 is the exit syscall code SWI 0 .data somedata: .word 4,2
.global _start _start: MOV R0, #1 MOV R1, #3 PUSH {R0, R1} BL get_value POP {R0, R1} B end get_value: MOV R0, #5 MOV R1, #7 ADD R2, R0, R1 BX LR end:
Actually wrote it before the video went into loops, with this exact example. The code is very different though.
.global _start _start: LDR R0, =list // array ptr MOV R1, #1 // current index LDR R2, [R0] // sum loop: LDR R3, [R0, #4]! // get value at current index and move array ptr forward ADD R2, R2, R3 // add current value to sum ADD R1, R1, #1 // increment index CMP R1, #10 BLT loop // index < 10 ? .data list: .word 1,2,3,4,5,6,7,8,9,10
Should be roughly equivalent to the following:
int main (void) { int list[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int idx = 1; int sum = *list; int r3; do { r3 = *(++list); sum += r3; idx += 1; } while (idx < 10); return 0; }
.global _start _start: MOV R0, #1 // stdout LDR R1, =message LDR R2, =len MOV R7, #4 // 4 is the write syscall code SWI 0 MOV R7, #1 // 1 is the exit syscall code SWI 0 .data message: .asciz "hello world" len = .-message
Roughly equivalent to the following:
int main (void) { const char msg[] = "hello world\n"; write(1, msg, sizeof(msg)); return 0; }
.global _start .equ endlist, 0xaaaaaaaa _start: // ...
At around 1h58min they show how to run an ARM VM in QEMU -- neat! Could be useful for other archs in the future.
$ as foo.s -o foo.o $ ld foo.o -o foo
Starting at around 2h22min they show some useful GDB functionality I didn't know about.
# Show in a TUI the CPU instructions around the current PC > layout asm # Present in a TUI the register contents > layout regs
<C-X><C-O> will jump between the GDB REPL and the other "windows".