2

我需要将我的代码从堆栈指针转换为仅使用帧指针,我该怎么做?我对 MIPS 很陌生。

我在下面有这个递归 C 代码及其 MIPS 代码。我正在使用堆栈指针,如何将其更改为使用帧指针?

这是我的 C 代码

int fact(int n)
{
    if(n!=1)
     return n*factorial(n-1);
}

    int comb (int n, int k)
    {
    return fact (n) / fact (k) / fact (n - k);
    }

这是我的 MIPS 代码

comb:           
 sub $sp, $sp, 16
 sw $ra , 0($sp)
 sw $s0, 4($sp) 
 sw $a0, 8($sp) 
 sw $a1, 12($sp)
 jal fact       
 move $s0, $v0  
 lw $a0, 12($sp) 
 jal fact       
 div $s0, $s0, $v0 
 lw $a0, 8($sp) 
 lw $a1, 12($sp) 
 sub $a0, $a0, $a1 
 jal fact       
 div $s0, $s0, $v0 
 move $v0, $s0  
 lw  $ra, 0($sp) 
 lw  $s0, 4($sp) 
 addi $sp, $sp, 16 
 jr $ra         
4

3 回答 3

6

我发现@markgz 的评论很有趣。他与维基百科的链接包括以下引用:

帧指针 ($30) 是可选的,实际上很少使用,除非函数中的堆栈分配是在运行时确定的,例如,通过调用 alloca()。

我总是觉得这$fp似乎是多余的,但无论如何我总是使用它,因为这就是我被教导这样做的方式。

无论如何,如果您仍然感兴趣,这是我使用帧指针的方式:

#save $ra $s0, $a0 on stack
addi $sp $sp -4
sw   $fp 0($sp)
move $fp $sp
addi $sp $sp -12
sw   $ra  -4($fp)
sw   $a0  -8($fp)
sw   $s0 -12($fp)

...

#restore and shrink stack
lw $s0 -12($fp)
lw $ra  -4($fp)
lw $fp   0($fp)
addi $sp $sp 16

jr $ra

所以每次展开栈时,我使用栈指针来保存帧指针的旧值,然后在收缩栈时恢复帧指针的旧值。

大多数情况下,我每次编写新函数时都会复制并粘贴此代码。

于 2014-04-17T02:53:23.343 回答
2

永远不应将 MIPS 代码转换为使用帧指针而不是堆栈指针,因为这将违反 MIPS调用约定,并且您的代码将停止与其他人的代码一起使用。

帧指针通常不用于手动编码的 MIPS 汇编器,因为堆栈指针在函数执行期间不会改变值。实际上,您自己的代码已正确编码,因此堆栈指针永远不会更改值。

于 2014-04-13T02:17:10.373 回答
0

扩展康拉德林登巴赫的答案:

#save $ra, $s0, $a0, $a1
addi $sp, $sp, -4
sw $fp, 0($sp)
move $fp, $sp
addi $sp, $sp, -16
sw $ra, -4($fp)
sw $a0, -8($fp)
sw $a1, -12($fp)
sw $s0, -16($fp)


#Your Code Here


#Restore
lw $s0, -16($fp)
lw $ra, -4($fp) #Can Be C+P'd from here down

addi $sp, $fp, 4 #restore $sp
lw $fp, 0($fp) #restore $fp

jr $ra #return to caller

这种方式在不牺牲指令长度的情况下更容易读写。您也可以将此方法用于动态内存分配,因为恢复代码段不需要知道分配给堆栈的数据量。

于 2018-04-27T00:32:42.357 回答