.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