在字符串中的每个字符上调用子例程 - MIPS

时间:2015-08-25 12:40:24

标签: string assembly 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

1 个答案:

答案 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