Recursion MIPS汇编中的简单递归问题
所以我试着用mips写一个程序,只做一些简单的递归,我读了关于这个主题的每一篇文章和问题,但是没有用。不管怎么说,我正试着把我的名字倒排出来。因此,我一次读取一个字节,查找字符串末尾的0,如果找到它,我将开始展开并打印保存的字节。 提前感谢您的帮助 代码:Recursion MIPS汇编中的简单递归问题,recursion,assembly,mips,Recursion,Assembly,Mips,所以我试着用mips写一个程序,只做一些简单的递归,我读了关于这个主题的每一篇文章和问题,但是没有用。不管怎么说,我正试着把我的名字倒排出来。因此,我一次读取一个字节,查找字符串末尾的0,如果找到它,我将开始展开并打印保存的字节。 提前感谢您的帮助 代码: 有一些问题 加载$t6应该是一个字节操作。否则,的条件分支的意义不正确。打印的系统调用应该是11[putc],而不是4[put]。处的堆栈帧还原有问题,否则 我已经创建了三个版本。显示错误的注释版本。一个清理和工作的版本。我从头开始创建了一个
有一些问题 加载
$t6
应该是一个字节操作。否则,的条件分支的意义不正确。打印的系统调用应该是11[putc
],而不是4[put
]。处的堆栈帧还原有问题,否则
我已经创建了三个版本。显示错误的注释版本。一个清理和工作的版本。我从头开始创建了一个版本
以下是带注释的版本[请原谅不必要的样式清理]:
.data
Yn: .asciiz "frodobaggins" # yn stands for your name
# print name backwards
.text
main:
li $v0,4 # syscall for print string
la $a1,Yn # load Yn's address into a0
addi $sp,$sp,-4 # increment stack pointer
sw $a1,0($sp) # store address of a1 (Yn) into stack pointer
jal recurse # recursive func call
addi $sp,$sp,4 # increment sp back to beggining
addi $v0,$0,10 # v0 = exit
syscall # exit
recurse:
lw $a3,0($sp) # load my name into reg $a3
# NOTE/BUG: this should be lb
# NOTE/BUG: by loading $t6 _before_ we've saved it, we are destroying the
# value that _caller_ set
###lw $t6,0($a3) # read byte
lb $t6,0($a3) # read byte
addi $sp,$sp,-12 # increment stack ptr
sw $ra,8($sp) # store address of $ra onto stack
sw $t6,4($sp) # store the byte loaded into $t6 onto stack
# NOTE/BUG: this should be beq and _not_ bne
###bne $t6,$0,otherwise # if t6 == 0 goto otherwise
beq $t6,$0,otherwise # if t6 == 0 goto otherwise
add $a3,$a3,1 # a1 = a1 + 1
sw $a3,0($sp) # push the word, without the byte $t6 used
jal recurse
lw $t6,4($sp) # load the byte that was stored into $t6
lw $ra,8($sp) # get $ra ready for returning
# NOTE/BUG: this is the puts syscall -- what we want is putc (i.e. 11)
###addi $v0,$0,4 # setup $v0 to tell pc to print to console
addi $v0,$0,11 # setup $v0 to tell pc to print to console
# NOTE/BUG: we want to load the byte into $a0
# NOTE/BUG: at this point $t6 has the byte value and _not_ a pointer
###lw $a0,0($t6) # console always reads from $a0
move $a0,$t6
syscall
addi $sp,$sp,12 # put stack pointer back
jr $ra # string is finished, return.
otherwise:
# because this is just returning, i need to get the ra that was just
# stored on the stack
lw $ra,8($sp)
# NOTE/BUG: by _not_ restoring the $t6 value of _caller_ things are broken
jr $ra # go back to original call of jal
这是工作版本。注意早期堆栈帧设置和在处弹出的完整堆栈帧,否则
。这是比较常见的。也就是说,只有一个地方可以建立堆栈框架。而且,只有一个位置可以弹出框架并返回:
.data
Yn: .asciiz "frodobaggins" # yn stands for your name
# print name backwards
.text
main:
li $v0,4 # syscall for print string
la $a1,Yn # load Yn's address into a0
addi $sp,$sp,-4 # increment stack pointer
sw $a1,0($sp) # store address of a1 (Yn) into stack
jal recurse # recursive func call
addi $sp,$sp,4 # increment sp back to beggining
addi $v0,$0,10 # v0 = exit
syscall # exit
recurse:
lw $a3,0($sp) # load my name into reg $a3
lb $t6,0($a3) # read byte
addi $sp,$sp,-12 # establish stack frame
sw $ra,8($sp) # store address of $ra onto stack
sw $t6,4($sp) # store the byte loaded into $t6 onto stack
beq $t6,$0,otherwise # if t6 == 0 goto otherwise
add $a3,$a3,1 # a1 = a1 + 1
sw $a3,0($sp) # push the word, without the byte $t6 used
jal recurse
lw $t6,4($sp) # load the byte that was stored into $t6
lw $ra,8($sp) # get $ra ready for returning
addi $v0,$0,11 # setup $v0 to tell pc to print to console
move $a0,$t6
syscall
otherwise:
lw $ra,8($sp) # restore return address from stack
lw $t6,4($sp) # store the byte loaded into $t6 onto stack
addi $sp,$sp,12 # put stack pointer back
jr $ra # string is finished, return.
这是我的重构版本。它更符合mips ABI。可能有一些细微的变化:
.data
name: .asciiz "frodobaggins"
nl: .asciiz "\n"
.text
.globl main
main:
li $v0,4 # print string syscall
la $a0,name # string address
syscall
li $v0,4 # print string syscall
la $a0,nl # string address
syscall
la $a0,name # string address
jal recurse1
li $v0,4 # print string syscall
la $a0,nl # string address
syscall
li $v0,10
syscall
# recurse1 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse1:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
sw $a0,0($sp) # save current string pointer
lb $t0,0($a0) # get current byte
beqz $t0,recurse1_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse1 # print other chars
subu $a0,$a0,1 # go back to our character
lb $a0,0($a0) # get current byte
li $v0,11 # putc syscall number
syscall
recurse1_exit:
lw $ra,4($sp) # restore return address
lw $a0,0($sp) # restore current string pointer
add $sp,$sp,8 # pop stack frame
jr $ra # return
# recurse2 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse2:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
sw $a0,0($sp) # save current string pointer
lb $t0,0($a0) # get current byte
beqz $t0,recurse2_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse2 # print other chars
lw $a0,0($sp) # restore our pointer
lb $a0,0($a0) # get current byte
li $v0,11 # putc syscall number
syscall
recurse2_exit:
lw $ra,4($sp) # restore return address
lw $a0,0($sp) # restore current string pointer
add $sp,$sp,8 # pop stack frame
jr $ra # return
# recurse3 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse3:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
lb $t0,0($a0) # get current byte
sw $t0,0($sp) # save current char value
beqz $t0,recurse3_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse3 # print other chars
lw $a0,0($sp) # get current byte
li $v0,11 # putc syscall number
syscall
recurse3_exit:
lw $ra,4($sp) # restore return address
add $sp,$sp,8 # pop stack frame
jr $ra # return
有一些问题
加载$t6
应该是一个字节操作。否则,的条件分支的意义不正确。打印的系统调用应该是11[putc
],而不是4[put
]。处的堆栈帧还原有问题,否则
我已经创建了三个版本。显示错误的注释版本。一个清理和工作的版本。我从头开始创建了一个版本
以下是带注释的版本[请原谅不必要的样式清理]:
.data
Yn: .asciiz "frodobaggins" # yn stands for your name
# print name backwards
.text
main:
li $v0,4 # syscall for print string
la $a1,Yn # load Yn's address into a0
addi $sp,$sp,-4 # increment stack pointer
sw $a1,0($sp) # store address of a1 (Yn) into stack pointer
jal recurse # recursive func call
addi $sp,$sp,4 # increment sp back to beggining
addi $v0,$0,10 # v0 = exit
syscall # exit
recurse:
lw $a3,0($sp) # load my name into reg $a3
# NOTE/BUG: this should be lb
# NOTE/BUG: by loading $t6 _before_ we've saved it, we are destroying the
# value that _caller_ set
###lw $t6,0($a3) # read byte
lb $t6,0($a3) # read byte
addi $sp,$sp,-12 # increment stack ptr
sw $ra,8($sp) # store address of $ra onto stack
sw $t6,4($sp) # store the byte loaded into $t6 onto stack
# NOTE/BUG: this should be beq and _not_ bne
###bne $t6,$0,otherwise # if t6 == 0 goto otherwise
beq $t6,$0,otherwise # if t6 == 0 goto otherwise
add $a3,$a3,1 # a1 = a1 + 1
sw $a3,0($sp) # push the word, without the byte $t6 used
jal recurse
lw $t6,4($sp) # load the byte that was stored into $t6
lw $ra,8($sp) # get $ra ready for returning
# NOTE/BUG: this is the puts syscall -- what we want is putc (i.e. 11)
###addi $v0,$0,4 # setup $v0 to tell pc to print to console
addi $v0,$0,11 # setup $v0 to tell pc to print to console
# NOTE/BUG: we want to load the byte into $a0
# NOTE/BUG: at this point $t6 has the byte value and _not_ a pointer
###lw $a0,0($t6) # console always reads from $a0
move $a0,$t6
syscall
addi $sp,$sp,12 # put stack pointer back
jr $ra # string is finished, return.
otherwise:
# because this is just returning, i need to get the ra that was just
# stored on the stack
lw $ra,8($sp)
# NOTE/BUG: by _not_ restoring the $t6 value of _caller_ things are broken
jr $ra # go back to original call of jal
这是工作版本。注意早期堆栈帧设置和在处弹出的完整堆栈帧,否则
。这是比较常见的。也就是说,只有一个地方可以建立堆栈框架。而且,只有一个位置可以弹出框架并返回:
.data
Yn: .asciiz "frodobaggins" # yn stands for your name
# print name backwards
.text
main:
li $v0,4 # syscall for print string
la $a1,Yn # load Yn's address into a0
addi $sp,$sp,-4 # increment stack pointer
sw $a1,0($sp) # store address of a1 (Yn) into stack
jal recurse # recursive func call
addi $sp,$sp,4 # increment sp back to beggining
addi $v0,$0,10 # v0 = exit
syscall # exit
recurse:
lw $a3,0($sp) # load my name into reg $a3
lb $t6,0($a3) # read byte
addi $sp,$sp,-12 # establish stack frame
sw $ra,8($sp) # store address of $ra onto stack
sw $t6,4($sp) # store the byte loaded into $t6 onto stack
beq $t6,$0,otherwise # if t6 == 0 goto otherwise
add $a3,$a3,1 # a1 = a1 + 1
sw $a3,0($sp) # push the word, without the byte $t6 used
jal recurse
lw $t6,4($sp) # load the byte that was stored into $t6
lw $ra,8($sp) # get $ra ready for returning
addi $v0,$0,11 # setup $v0 to tell pc to print to console
move $a0,$t6
syscall
otherwise:
lw $ra,8($sp) # restore return address from stack
lw $t6,4($sp) # store the byte loaded into $t6 onto stack
addi $sp,$sp,12 # put stack pointer back
jr $ra # string is finished, return.
这是我的重构版本。它更符合mips ABI。可能有一些细微的变化:
.data
name: .asciiz "frodobaggins"
nl: .asciiz "\n"
.text
.globl main
main:
li $v0,4 # print string syscall
la $a0,name # string address
syscall
li $v0,4 # print string syscall
la $a0,nl # string address
syscall
la $a0,name # string address
jal recurse1
li $v0,4 # print string syscall
la $a0,nl # string address
syscall
li $v0,10
syscall
# recurse1 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse1:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
sw $a0,0($sp) # save current string pointer
lb $t0,0($a0) # get current byte
beqz $t0,recurse1_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse1 # print other chars
subu $a0,$a0,1 # go back to our character
lb $a0,0($a0) # get current byte
li $v0,11 # putc syscall number
syscall
recurse1_exit:
lw $ra,4($sp) # restore return address
lw $a0,0($sp) # restore current string pointer
add $sp,$sp,8 # pop stack frame
jr $ra # return
# recurse2 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse2:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
sw $a0,0($sp) # save current string pointer
lb $t0,0($a0) # get current byte
beqz $t0,recurse2_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse2 # print other chars
lw $a0,0($sp) # restore our pointer
lb $a0,0($a0) # get current byte
li $v0,11 # putc syscall number
syscall
recurse2_exit:
lw $ra,4($sp) # restore return address
lw $a0,0($sp) # restore current string pointer
add $sp,$sp,8 # pop stack frame
jr $ra # return
# recurse3 -- reverse print string
#
# arguments:
# a0 -- current string pointer
recurse3:
sub $sp,$sp,8 # create stack frame
sw $ra,4($sp) # save return address
lb $t0,0($a0) # get current byte
sw $t0,0($sp) # save current char value
beqz $t0,recurse3_exit # is it EOS? if yes, fly
addu $a0,$a0,1 # advance to next char
jal recurse3 # print other chars
lw $a0,0($sp) # get current byte
li $v0,11 # putc syscall number
syscall
recurse3_exit:
lw $ra,4($sp) # restore return address
add $sp,$sp,8 # pop stack frame
jr $ra # return
你没有问任何问题,是吗?lw$t6,0($a3)#读取字节
lw
不加载字节;它加载一个单词(4个字节)。我最初将它作为lb,但现在它运行,但实际上不会打印任何内容,所以我将它改为lw,看看我是否至少可以让控制台以这种方式打印一些内容,你不会问任何问题,是吗?lw$t6,0($a3)#读取字节
lw
不加载字节;它加载一个字(4字节)。我最初把它作为lb,但现在它运行,但实际上不会打印任何东西,所以我把它改为lw,看看我是否至少可以让控制台以这种方式打印东西