我是MIPS程序集的新手,我想写一个例程,它接受一个字符串的内存地址和另一个回调子程序的内存地址。此例程将遍历字符串中的每个字母,并为每个字母调用子例程(这将打印每个字母的ASCII值)。伪代码看起来像这样:
string_for_each(string, subroutine) {
for_each_character_in_string {
subroutine(address_of(character))
}
}
这就是我现在的惯例:
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
问题是寄存器$ a0包含字符串的地址,而$ a1包含回调子例程的地址,并且字符串中当前字符的地址也将被传递给回调子例程在$ a0。 $ a0如何同时包含字符串的起始地址和当前字符?
回调子程序:
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
答案 0 :(得分:1)
在子程序调用期间,您需要将$a0
和$a1
保存在其他地方(通常是堆栈)。此外,您的loop
不是子例程,没有理由使用jal
来调用它。另一方面,回调是子例程,您应该使用jalr
来调用它。这些方面应该有用:
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