对字符串中的每个字符调用子程序 - MIPS
Call a subroutine on each character in string - MIPS
我是 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
在子程序调用期间,您需要将 $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
我是 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
在子程序调用期间,您需要将 $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