223 lines
4.7 KiB
ArmAsm
223 lines
4.7 KiB
ArmAsm
.data
|
|
sp_start: .space 8
|
|
|
|
.section .text
|
|
.globl save_sp, fetch_argc, fetch_argv, has_switch, str_cmp
|
|
|
|
save_sp:
|
|
sd sp, sp_start, t0 # save the stack pointer
|
|
ret
|
|
|
|
# Fetch argument count
|
|
# @param[in] a0: unused.
|
|
# @param[out] a0: result code.
|
|
# @param[out] a1: number of arguments.
|
|
fetch_argc:
|
|
ld t0, sp_start
|
|
ld a1, 0(t0) # dereference the buffer
|
|
li a0, 0 # success
|
|
ret
|
|
|
|
# Fetch argument value
|
|
# @param[in] a0: argv[a0].
|
|
# @param[out] a0: result code.
|
|
# @param[out] a1: address of argv[a0].
|
|
# @param[out] a2: sizeof(argv[a0]).
|
|
fetch_argv:
|
|
addi sp, sp, -8
|
|
sd s0, 0(sp)
|
|
mv s0, a0
|
|
|
|
addi sp, sp, -16
|
|
sd ra, 8(sp)
|
|
sd s0, 0(sp)
|
|
call fetch_argc # get argument count
|
|
ld ra, 8(sp)
|
|
ld s0, 0(sp)
|
|
addi sp, sp, 16
|
|
|
|
bge s0, a1, 2f # fail if a0 larger than argc
|
|
bltz a1, 2f # fail if a0 less than zero
|
|
ld t0, sp_start
|
|
addi t0, t0, 8
|
|
addi sp, sp, -8
|
|
sd s1, 0(sp)
|
|
li s1, 0
|
|
|
|
ld a0, 0(t0)
|
|
|
|
1:
|
|
addi sp, sp, -24
|
|
sd ra, 16(sp)
|
|
sd s1, 8(sp)
|
|
sd s0, 0(sp)
|
|
call _next_argv # grab the next argument
|
|
ld ra, 16(sp)
|
|
ld s1, 8(sp)
|
|
ld s0, 0(sp)
|
|
addi sp, sp, 24
|
|
mv a0, a1
|
|
addi s1, s1, 1
|
|
bne s1, s0, 1b # if we haven't retrieved the requested argument, go again
|
|
|
|
j 3f
|
|
|
|
2:
|
|
li a0, 1 # fail
|
|
ld s0, 0(sp)
|
|
addi sp, sp, 8
|
|
ret
|
|
|
|
3:
|
|
mv s0, a1
|
|
addi sp, sp, -16
|
|
sd ra, 8(sp)
|
|
sd s0, 0(sp)
|
|
|
|
mv a0, a1
|
|
call _argv_size # grab the size of the retrieved argument
|
|
|
|
ld ra, 8(sp)
|
|
ld s0, 0(sp)
|
|
addi sp, sp, 16
|
|
|
|
li a0, 0
|
|
mv a2, a1
|
|
mv a1, s0
|
|
|
|
4:
|
|
ld s1, 0(sp)
|
|
addi sp, sp, 8
|
|
ld s0, 0(sp)
|
|
addi sp, sp, 8
|
|
ret
|
|
|
|
# Check if flag was given
|
|
# @param[in] a0: ptr to null-terminated switch 1 (ie. -h).
|
|
# @param[in] a1: ptr to null-terminated switch 2 (ie. --help) (optional, pass 0 for none).
|
|
# @param[out] a0: result code.
|
|
# @param[out] a1: was found (0-not found, 1-found).
|
|
has_switch:
|
|
addi sp, sp, -24 # store ra and s regs to stack
|
|
sd ra, 16(sp)
|
|
sd s1, 8(sp)
|
|
sd s0, 0(sp)
|
|
|
|
mv s0, a0
|
|
mv s1, a1
|
|
|
|
call fetch_argc
|
|
bnez a0, .LHasSwitchNoParse
|
|
li t0, 2
|
|
blt a1, t0, .LSwitchNotFoundNoParse # if we have no commands other than the binary, we know there will be no switches
|
|
|
|
addi sp, sp, -24
|
|
sd s4, 16(sp)
|
|
sd s2, 8(sp)
|
|
sd s3, 0(sp)
|
|
li s2, 1 # load first non-base command arg
|
|
mv s4, a1 # put argc in s4
|
|
|
|
.LSwitchProcessNextArg:
|
|
mv a0, s2
|
|
call fetch_argv
|
|
mv s3, a1 # save argv buff addr
|
|
|
|
mv a0, s3 # load argv buff addr into a0 (string 0)
|
|
mv a1, s0 # move switch ptr 1 addr into a1 (string 1)
|
|
call str_cmp
|
|
bnez a1, .LSwitchFound # if the strings match, exit loop
|
|
beqz s1, .LSkipSecondSwitch # if we have no second switch, skip the check
|
|
|
|
mv a0, s3 # move argv buff addr into a0 (string 0)
|
|
mv a1, s1 # move switch ptr 2 addr into a1 (string 1)
|
|
call str_cmp
|
|
bnez a1, .LSwitchFound # if the strings match, exit loop
|
|
|
|
.LSkipSecondSwitch:
|
|
addi s2, s2, 1 # if string doesn't match we inc to the next arg
|
|
blt s2, s4, .LSwitchProcessNextArg # keep going while we have untested args
|
|
|
|
.LSwitchNotFound:
|
|
li a0, 0
|
|
li a1, 0
|
|
j .LSwitchFreeSP
|
|
|
|
.LSwitchNotFoundNoParse:
|
|
li a0, 0
|
|
li a1, 0
|
|
j .LHasSwitchNoParse
|
|
|
|
.LSwitchFound:
|
|
li a0, 0
|
|
li a1, 1
|
|
|
|
.LSwitchFreeSP:
|
|
ld s3, 0(sp)
|
|
ld s2, 8(sp)
|
|
ld s4, 16(sp)
|
|
addi sp, sp, 24
|
|
|
|
.LHasSwitchNoParse:
|
|
ld ra, 16(sp)
|
|
ld s1, 8(sp)
|
|
ld s0, 0(sp)
|
|
addi sp, sp, 24 # restore ra and s regs from stack
|
|
ret
|
|
|
|
# Compares two null terminated string buffers.
|
|
# @param[in] a0: str buffer 1
|
|
# @param[in] a1: str buffer 2
|
|
# @param[out] a0: result code.
|
|
# @param[out] a1: is equal (0-no, 1-yes).
|
|
str_cmp:
|
|
li t2, 0
|
|
|
|
.LByteCmp:
|
|
add t0, a0, t2
|
|
add t1, a1, t2
|
|
lb t0, 0(t0)
|
|
lb t1, 0(t1)
|
|
bne t0, t1, .LNoMatch # first byte that isn't the same, branch to no match
|
|
beqz t0, .LMatch # jump to ret when null is read
|
|
addi t2, t2, 1
|
|
j .LByteCmp
|
|
|
|
.LNoMatch: # no match
|
|
li a0, 0
|
|
li a1, 0
|
|
ret
|
|
|
|
.LMatch: # match
|
|
li a0, 0
|
|
li a1, 1
|
|
ret
|
|
|
|
# Fetch argument value
|
|
# @param[in] a0: address of current argv.
|
|
# @param[out] a0: result code.
|
|
# @param[out] a1: address of next argv.
|
|
_next_argv:
|
|
lb t2, 0(a0) # deref val at reg
|
|
addi a0, a0, 1 # inc reg
|
|
bnez t2, _next_argv # deref val != 0
|
|
mv a1, a0
|
|
li a0, 0 # success
|
|
ret
|
|
|
|
# Fetch argument value
|
|
# @param[in] a0: address of argv.
|
|
# @param[out] a0: result code.
|
|
# @param[out] a1: address of next argv.
|
|
_argv_size:
|
|
li t0, 0
|
|
1:
|
|
lb t1, 0(a0) # deref val at reg
|
|
addi a0, a0, 1 # inc reg
|
|
addi t0, t0, 1
|
|
bnez t1, 1b # deref val != 0
|
|
|
|
mv a1, t0
|
|
li a0, 0 # success
|
|
ret
|