我目前在MIPS中编写这个递归阶乘汇编代码时遇到了麻烦。我不想改变这个代码的格式,因为它是一个项目,但我想了解如何存储或调用$ra,以便它将返回到“分支:“,以输出计算的阶乘。
##
##
.data
prompt1: .asciiz "\nPlease enter an integer: \n"
negativePrompt: .asciiz "\nYour input must be greater than or equal to 0 in order to function.\n"
factorialIs: .asciiz "\nThe factorial of your input number is: \n"
.globl main
.text
main:
subu $sp, $sp, 32 # push memory for 8 values
sw $ra, 20($sp) # save return address
sw $fp, 16($sp) # save old frame pointer
addiu $fp, $sp, 28 # set up frame pointer
branch:
li $v0, 4 # load macro for print_str
la $a0, prompt1 # pass argument to string
syscall # print string prompt1
li $v0, 5 # load macro for read_int
syscall # get N value from user
move $a0, $v0 # store N as arg
blt $a0, 0, negBranch # if N is negative, handles case
jal factorial # calls factorial function
li $v0, 4 # macro for print string
la $a0, factorialIs # print string
syscall
li $v0, 1 # macro for print int
move $a0, $v0 # print output int in v0
syscall
lw $ra, 20($sp) # restore return address of caller
lw $fp, 16($sp) # restore frame pointer
addiu $sp, $sp, 32 # pop stack
jr $ra # return to caller
#exit:
# "would you like to calculate again?"
# li $v0, 10 # load macro to exit
# syscall # execute exit
negBranch:
li $v0, 4 # load macro for print_str
la $a0, negativePrompt # pass argument to string
syscall # print string prompt1
li $t0, 0 # initialize input value to 0
j branch # ask user to input new number
factorial:
subu $sp, $sp, 32 # pushes memory for variables
sw $ra, 12($sp) # stores return address of recursion
sw $fp, 8($sp) # save frame pointer
addiu $fp, $sp, 28 # set up frame pointer
sw $a0, 0($fp) # stores n in frame pointer
lw $v0, 0($fp)
bgtz $v0, zeroBranch # if N is greater than 0, recurse
li $v0, 1 # return 1
jr end
zeroBranch:
lw $v1, 0($fp) # load n value
subu $v0, $v1, 1 # v0 = n - 1
move $a0, $v0 # a0 = v0 = n - 1
jal factorial # recursive function call
lw $v1, 0($fp) # load original n value to v1
mul $v0, $v0, $v1 # v0 = n * fact(n-1)
end:
lw $ra, 12($sp) # loads return address of main call
## this ^ line does not access the address from "jal factorial"
lw $fp, 16($sp) # loads initial n value
addiu $sp, $sp, 32 # collapses stack frame
jr $ra # return to main then exit
当我输入factorial(1)时,它如预期的那样递归地运行;然而,当我到达我的“end:”分支时,返回地址没有返回到我的“branch:”分支,它将输出阶乘输入的结果。
1条答案
按热度按时间pbpqsu0x1#
为什么你认为函数应该返回到标签
branch:
-这是本质上不正确的,所以你需要重新考虑这一点。函数应该立即返回到jal
之后的指令。这段代码有汇编时错误,所以我不知道你是如何运行它的。
jr end
不是一个有效的指令-我认为你需要j end
。在
factorial
的后记中,这段代码把$fp
寄存器搞乱了-旧的$fp
保存在8($sp)
,但从16($sp)
恢复,所以它不会回到调用者需要它的位置。用于在
main
中打印阶乘结果的系统调用序列是:你能看到这两行代码是如何破坏了
$v0
中你想要打印的值的,所以将总是打印1
吗?但比这更糟糕的是,因为您还打印了一个提示符(syscall #4,前面几行),它将4(打印字符串的syscall代码)移动到
$v0
中,消除了函数返回值。所以,要做的是:在
main
中的jal
指令之后,立即复制返回值$v0
,在不同的位置-建议$t0
,因为它将在syscall
中存活(如果它是一个函数调用,则建议内存或$s0
)。然后,在用于打印整数的系统调用#1处,将
$t0
复制到用于参数的$a0
中。您可以通过使用调试器中的单步调试来查看所有这些。调试是一项关键技能,任何尝试汇编语言编程的人都应该拥有它或尽快掌握它。单步调试并查看每行,验证每行之间的程序状态(寄存器和内存)。