/*#!as --gstabs+ -o sketch.o sketch.s && ld -o sketch -e _start sketch.o && objdump -d -j .text -j .data sketch && ./sketch | |
*/ | |
.global _start | |
.macro sys_exit | |
mov r7, $0x01 /* set system call number to 1 (exit) */ | |
svc $0x00 /* supervisor call */ | |
.endm | |
.macro sys_write | |
mov r7, $0x04 | |
svc $0x00 /* supervisor call */ | |
.endm | |
_start: | |
mov lr, #0 | |
/* r0 = argc */ | |
ldr r0, [sp] | |
/* r1 = argv */ | |
add r1, sp, $0x04 | |
/* r2 = argc * 4 (skip argv) */ | |
mov r3, $0x04 | |
mul r2, r0, r3 | |
/* r2 += 4 (skip null word) */ | |
add r2, r2, $0x04 | |
/* r2 += offset (ok this is environ) */ | |
add r2, r1 | |
/* save char** environ to global variable */ | |
ldr r3, =environ | |
str r2, [r3] | |
/* r0 = argc, r1 = argv, r2 = environ */ | |
bl main | |
/* not reached */ | |
mov r0, $0xff | |
sys_exit | |
main: | |
/* getenv("USER") */ | |
adr r0, USER | |
bl getenv | |
/* if "USER" is not in ENV */ | |
cmp r0, $0x00 | |
bleq error | |
bl puts | |
mov r0, $0x00 /* set exit status to 0 */ | |
sys_exit | |
USER: | |
.asciz "USER" | |
.align 2 | |
error: | |
mov r0, $0x01 | |
sys_exit | |
strncmp: /* char* s1, char* s2, size_t len -> 1|0 */ | |
stmfd sp!, {v1-v5, lr} /* save variable resistors and returning address */ | |
mov r3, $0x00 /* result */ | |
1: cmp r2, $0x00 | |
beq 2f /* if (r2 == 0) goto 2 */ | |
sub r2, r2, $0x01 /* len-- */ | |
ldrb r4, [r0], $0x01 /* r4 = *s1++ */ | |
ldrb r5, [r1], $0x01 /* r5 = *s2++ */ | |
cmp r4, r5 | |
beq 1b /* if (r4 == r5) goto 1 */ | |
add r3, $0x01 /* r3++ (this function always returns 1 when the comparing fails) */ | |
2: | |
mov r0, r3 | |
ldmfd sp!, {v1-v5, pc} /* restore variable resistors and set pc to returning address */ | |
strlen: /* char* str* -> uint */ | |
mov r1, $0x00 /* r1 = result */ | |
/* r2 = *str++ (ldrb = load byte, and r0 increment after) */ | |
1: ldrb r2, [r0], $0x01 | |
cmp r2, $0x00 | |
addne r1, r1, $0x01 /* if (r2 != 0) r1++ */ | |
bne 1b /* if (r2 != 0) goto 1; */ | |
mov r0, r1 | |
mov pc, lr | |
getenv: /* char* name -> char* */ | |
stmfd sp!, {v1-v5, lr} | |
/* v1 = name */ | |
mov v1, r0 | |
/* v2 = strlen(r0) */ | |
bl strlen | |
mov v2, r0 | |
/* v3 = environ char** */ | |
ldr v3, =environ | |
ldr v3, [v3] | |
1: /* if (strncmp(name, *environ, len) == 0) { */ | |
mov r0, v1 | |
ldr r1, [v3] | |
/* *environ != NULL */ | |
cmp r1, $0x00 | |
beq 2f | |
mov r2, v2 | |
bl strncmp | |
cmp r0, $0x00 | |
/* if (*environ)[len] == '=') { */ | |
ldreq r0, [v3] | |
ldreqb r0, [r0, v2] | |
cmpeq r0, #'= | |
beq 3f | |
/* } */ | |
/* environ++ */ | |
add v3, $0x04 | |
b 1b | |
2: | |
/* not found return NULL */ | |
mov r0, $0x00 | |
ldmfd sp!, {v1-v5, pc} | |
3: /* found and return address */ | |
ldreq r0, [v3] | |
add r0, r0, v2 | |
add r0, r0, $0x01 /* skip '=' */ | |
ldmfd sp!, {v1-v5, pc} | |
puts: | |
stmfd sp!, {v1-v5, lr} | |
mov v1, r0 | |
bl strlen | |
mov r2, r0 | |
mov r1, v1 | |
mov r0, $0x00 | |
sys_write | |
mov r0, $0x00 | |
adr r1, linefeed | |
mov r2, $0x01 | |
sys_write | |
ldmfd sp!, {v1-v5, pc} | |
linefeed: | |
.byte '\n | |
.align 2 | |
.section .bss | |
.align 2 | |
environ: .word 0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment