我的任务:编写一个汇编程序,使用递归将数字 42 添加到总和 𝑛 次,其中 𝑛 由输入给出。
我遇到的问题是,每次输入一个值时,都会返回相同的值,而不返回递归解。比如我输入5,输出是5。
这是我的汇编代码:
.text
.globl meaning_of_life
.type meaning_of_life, @function
meaning_of_life:
addi sp, sp, -16 # Allocate stack space for this frame
sd ra, 8(sp) # Save the return address
sd a0, 0(sp) # Save the original value of n
li t0, 42 # Load 42 into temporary register t0
beqz a0, base_case # If n is 0, jump to base_case
addi a0, a0, -1 # Decrement n
call meaning_of_life # Recursive call
add a0, a0, t0 # Add 42 to the result of the recursion
ld ra, 8(sp) # Restore the return address
ld a0, 0(sp) # Optionally restore original n, if needed for other logic
addi sp, sp, 16 # Deallocate stack space
ret # Return to the caller
base_case:
li a0, 0 # Base case: the sum is 0
ld ra, 8(sp) # Restore the return address
addi sp, sp, 16 # Deallocate stack space
ret # Return to the caller
这是我运行递归汇编文件的 C 代码:
#include <stdio.h>
#include <stdint.h> // Include for int32_t
// Declaration of the assembly function using int32_t
extern int32_t meaning_of_life(int32_t n);
int main() {
int32_t n, result;
// Prompt the user for input
printf("Enter a number: ");
scanf("%d", &n); // Use %d for int32_t as well, it's typically fine for most platforms
// Call the assembly function
result = meaning_of_life(n);
// Print the result
printf("The result of adding 42 to the number %d times is: %d\n", n, result);
return 0;
}
返回值在
a0
中。它返回输入,因为您明确告诉它:
ld a0, 0(sp) # Optionally restore original n, if needed for other logic
有时,我们需要保留传入
a
寄存器中的原始值,以供我们的函数在其主体内部使用,并且我们可以将其保存在堆栈中。
但我们永远不会为了调用者的利益而在尾声中恢复
a
或 t
寄存器 - 他们不希望如此,因此不会利用这一点(模自定义调用约定)。
您的代码在递归调用后不需要
n
,因此在序言中保存 a0
是没有意义的。
正如已经指出的,根据标准调用约定,不希望
t0
在函数调用后继续存在,并且由于它加载了一个常量,所以最好的方法(从寄存器的角度来看)就是简单地将其延迟到稍后在函数调用之后(是的,它会立即生效,所以甚至不需要寄存器)。在您的情况下,t0
寄存器将始终为42,因为该寄存器没有以其他方式使用,但依赖于此确实违反了标准调用约定。
您应该考虑编写该函数的 C 版本
int meaning_of_life(int);
。通常,更容易理解为什么事情会在高级语言中按照应有的方式工作,并且还可以看到我们实际上正在做汇编中所需的事情,仅此而已。
您可以从 C 代码开始实时变量分析,以确定哪些变量在调用中是实时的,哪些不是,并且在进行汇编之前查看高级语言形式会很有用。
int meaning_of_life ( int n ) {
if ( n == 0 ) return 0;
return meaning_of_life ( n-1 ) + 42;
}
在这里您可以看到
n
不在通话中实时显示,因此不需要特别注意或存储。一旦进行函数调用,n
就不再被引用,仅通过加法进一步使用函数调用的返回值。