Skip to content

Instantly share code, notes, and snippets.

@seenaburns
Last active March 11, 2023 18:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seenaburns/70019f3217ab6392c3c245976e336978 to your computer and use it in GitHub Desktop.
Save seenaburns/70019f3217ab6392c3c245976e336978 to your computer and use it in GitHub Desktop.
ARM assembly to take parse argv[1], argv[2] as ints, add them, and print them back to stdout
// Building (on x86):
//
// arm-linux-gnueabi-as -o strtoi-add-argv.o strtoi-add-argv.s
// arm-linux-gnueabi-ld -o strtoi-add-argv strtoi-add-argv.o
//
// Running:
// qemu-arm strtoi-add-argv 100 23; echo $?
//
.data
Input:
.ascii "89\0"
NewlineString:
.ascii "\n\0"
TestString:
.ascii "Some string\n\0"
.text
.global _start
_start:
ldr r4, [sp] // argc
ldr r5, [sp, #8] // argv[1]
ldr r6, [sp, #12] // argv[2]
sub sp, sp, #12 // allocate a string buf
add r1, sp, #0 // r1 point to string buf
sub sp, sp, #16 // allocate some scratch space to save registers
// strtoi argv[1], stored in r5
mov r0, r5
bl strtoi
mov r5, r0
// strtoi argv[2], stored in r6
mov r0, r6
bl strtoi
mov r6, r0
// r0 = argv[1] + argv[2]
add r0, r5, r6
bl itostr
mov r0, r1
// ldr r0, =TestString
bl print
ldr r0, =NewlineString
bl print
// Exit
mov r7, #1
mov r0, #1 // exit code
svc #0
/*
strtoi:
r0: pointer to string
return:
r0: int
clobber:
r0
*/
strtoi:
push {r11, lr}
add r11, sp, #0
sub sp, sp, #20
push {r1,r2,r3,r4,r5}
mov r3, r0 // copy addr to r3, r0 is clobbered
mov r1, #0 // r1 is index, set to 0
mov r2, #0 // r2 is running total
mov r4, #10
strtoi_loop:
// load next char, exit loop if null
ldrb r0, [r3, r1]
cmp r0, #0
beq strtoi_end
// mult current total by 10
mul r5, r2, r4
mov r2, r5
// parse and add next char
// ascii -> int: x - '0' offset (48)
sub r0, r0, #48
add r2, r2, r0
// incr index by 1 byte and continue
add r1, r1, #1
bl strtoi_loop
strtoi_end:
mov r0, r2 // copy total to output
pop {r1,r2,r3,r4,r5}
sub sp, r11, #0
pop {r11, pc}
/*
itostr:
r0: int
r1: pointer to str
return:
clobber:
r0
*/
itostr:
push {r11, lr}
add r11, sp, #0
sub sp, sp, #20
push {r1,r2,r3,r4,r5}
mov r2, #0 // r2 is index, set to 0
mov r3, r0 // r3 is remaining sum
itostr_loop:
// calc r3 mod 10
// use r4 as temp for quotient, r5 for mod
mov r8, #10
udiv r4, r3, r8
mls r5, r4, r8, r3
// convert to ascii and add to string
add r6, r5, #48
// mov r6, #65
strb r6, [r1, r2]
// Incr index for next
add r2, r2, #1
// Use remaining sum for next iteration
mov r3, r4
cmp r3, #0
beq itostr_end
bl itostr_loop
itostr_end:
mov r4, #0
strb r4, [r1, #4]
mov r0, r1
bl reverse
pop {r1,r2,r3,r4,r5}
sub sp, r11, #0
pop {r11, pc}
/*
reverse: reverse string in place
r0: pointer to str
return:
clobber:
r0-5
*/
reverse:
push {r11, lr}
add r11, sp, #0
sub sp, sp, #4
push {r0}
bl strlen
mov r3, r0 // length
pop {r0}
mov r1, #0 // r1 is start offset
mov r2, r3 // r2 is end offset
sub r2, r2, #1
reverse_loop:
cmp r1, r2
blge reverse_end
ldrb r3, [r0, r1] // load start
ldrb r4, [r0, r2] // load start
// swap
strb r4, [r0, r1]
strb r3, [r0, r2]
add r1, r1, #1
sub r2, r2, #1
bl reverse_loop
reverse_end:
sub sp, r11, #0
pop {r11, pc}
// r0: address of message
// clobber r0-r2
print:
push {r11, lr}
add r11, sp, #0
sub sp, sp, #16
push {r0}
bl strlen
mov r2, r0 // length
pop {r0}
mov r1, r0 // msg
// Write
mov r7, #4 // write syscall
mov r0, #1 // fd
svc #0
sub sp, r11, #0
pop {r11, pc}
/*
strlen: return count of c string
r0: pointer to string
return:
r0: int
clobber:
r0-2
*/
strlen:
push {r11, lr}
add r11, sp, #0
mov r2, r0 // copy addr to r2, r0 is clobbered
mov r1, #0 // r1 is index, set to 0
strlen_loop:
ldrb r0, [r2, r1] // load + parse next character
cmp r0, #0
beq strlen_end
add r1, r1, #1
bl strlen_loop
strlen_end:
mov r0, r1 // copy result to output
sub sp, r11, #0
pop {r11, pc}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment