问题
I'm new to MIPS assembly, I want to write a routine that takes the memory address of a string and the memory address of another callback subroutine. This routine will go through every letter in the string and for each letter call the subroutine (this prints the ASCII value of each letter). The pseudo code would look something like this:
string_for_each(string, subroutine) {
for_each_character_in_string {
subroutine(address_of(character))
}
}
This is what my routine looks like right now:
string_for_each:
addi $sp, $sp, -4 # PUSH return address to caller
sw $ra, 0($sp)
jal loop
lw $ra, 0($sp) # Pop return address to caller
addi $sp, $sp, 4
jr $ra
loop:
lb $t1, 0($a0) # Get current character
beq $t1, $zero, end_for_each # Done when reaching NULL character
jr $a1 # Call callback subroutine
addi $a0, $a0, 1 # Increment to get next character in string
j loop
end_for_each:
jr $ra # Return to caller
The thing is that the register $a0 contains the address to the string, and $a1 contains the address to the callback subroutine, and the address to the current character in the string that will be passed to the callback subroutine should also be in $a0. How can $a0 contain both the starting address of the string and the current character at the same time?
The callback subroutine:
ascii:
.data
STR_the_ascii_value_is:
.asciiz "\nAscii('X') = "
.text
la $t0, STR_the_ascii_value_is
# Replace X with the input character
add $t1, $t0, 8 # Position of X
lb $t2, 0($a0) # Get the Ascii value
sb $t2, 0($t1)
# Print "The Ascii value of..."
add $a0, $t0, $zero
li $v0, 4
syscall
# Append the Ascii value
add $a0, $t2, $zero
li $v0, 1
syscall
jr $ra
回答1:
You will need to save $a0
and $a1
elsewhere (usually stack) for the duration of the subroutine call. Also, your loop
isn't a subroutine, no reason to call it using jal
. On the other hand, the callback is a subroutine, you should call it using jalr
. Something along these lines should work:
string_for_each:
addiu $sp, $sp, -12 # Need 3 locals for $a0, $a1 and $ra
sw $ra, 0($sp) # Store $ra
sw $a1, 8($sp) # Store $a1
loop:
sw $a0, 4($sp) # Store $a0 as it will be used for argument
lb $t0, 0($a0) # Get current character
beq $t0, $zero, end_for_each # Done when reaching NULL character
jalr $a1 # Call callback subroutine
lw $a0, 4($sp) # Reload $a0
lw $a1, 8($sp) # $a1 could have changed (calling convention)
addi $a0, $a0, 1 # Increment to get next character in string
j loop
end_for_each:
lw $ra, 0($sp) # Reload return address to caller
addiu $sp, $sp, 12 # Free locals
jr $ra
来源:https://stackoverflow.com/questions/32204287/call-a-subroutine-on-each-character-in-string-mips