对字符串中的每个字符调用子程序 - 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