此MIPS过程调用的错误是什么?

此MIPS过程调用的错误是什么?,mips,call,procedure,Mips,Call,Procedure,此MIPS代码包含一个调用另一个函数foo(a,b)的函数int func(int a,int b) 此代码包含一些错误,但我不知道哪里出错。最严重的违规行为是func期望$a1在对foo的函数调用中幸存下来,这是不正确的。根据调用约定,$a1是一个参数寄存器,不由函数调用保留$a1也不是返回值,因此在函数调用后应将其视为未初始化,即它包含uselss垃圾 func: addi $sp,$sp,-4 sw $ra, 0($sp) addi $a0,$a0,

此MIPS代码包含一个调用另一个函数foo(a,b)的函数int func(int a,int b)


此代码包含一些错误,但我不知道哪里出错。

最严重的违规行为是
func
期望
$a1
在对
foo
的函数调用中幸存下来,这是不正确的。根据调用约定,
$a1
是一个参数寄存器,不由函数调用保留
$a1
也不是返回值,因此在函数调用后应将其视为未初始化,即它包含uselss垃圾

func: addi $sp,$sp,-4    
      sw $ra, 0($sp)    
      addi $a0,$a0,1    
      addi $a1,$a1,2    
      jal foo           # this call effectively wipes out argument registers (ok)
      addi $a0,$v0,4    # here the function re-initializes $a0 from return value $v0 (ok)
      add $v0,$a0,$a1   # but here it uses uninitliazed $a1 (not ok)
      lw $ra,0($sp)    
      addi $sp,$sp,4    
      jr $ra
保存
func
s
$a1
参数的正确方法是将其存储在内存中,并在函数调用后重新加载;这需要在堆栈帧中添加一个字

func: addiu $sp,$sp,-8    
      sw $ra, 4($sp)    
      addi $a0,$a0,1    
      addi $a1,$a1,2 
      sw $a1, 0($sp)    # save a1 in stack before call
      jal foo           # this call effectively wipes out argument registers
      lw $a1, 0($sp)    # restore a1 from stack after call
      addi $a0,$v0,4    # here the function re-initializes $a0 from return value $v0
      add $v0,$a0,$a1   # now using re-initialized $a1 (ok)
      lw $ra,4($sp)    
      addiu $sp,$sp,8    
      jr $ra
在上面,我保存了更新后的
$a1
寄存器,但可以肯定的是,仅仅读取代码并不清楚原始的、未递增的
$a1
还是更新后的
$a1
。看起来,
$a1
是作为参数传递给foo的,因此可能是
foo
想要递增的值,但
func
以后不需要

或者,可以将
$a1
存储在
$s
寄存器中,因为调用约定可以确保在整个函数调用过程中保留这些寄存器-但是,根据这个定义,
$s
寄存器本身,如果被调用方使用,则必须保存和恢复,因此,仍然需要在堆栈框架中添加一个字


其他违反MIPS呼叫约定的行为包括:

  • MIPS CC要求堆栈帧是8字节对齐的,因此即使您只需要一个字,我们也应该将堆栈帧大小四舍五入到8字节的倍数。然而,许多汇编程序员忽略了这一点,却没有造成严重后果

  • MIPS CC还指定要保存在堆栈中的4个参数寄存器的空间,并且该空间由调用者提供,以便被调用者可以使用它(无需被调用者进行任何堆栈分配)。虽然在技术上是必需的,但汇编程序员几乎从未在简单的任务中完成过这项工作。如果被叫人利用了这4个本来应该在那里的词,而它们不在那里,坏事就会发生。(我没有在上面的解决方案中提到这一点。)在编写调用函数的函数时,如printf、sprintf、scanf等,我至少会遵循这一要求。。4个参数寄存器的存储区域与第5、6等的内存相邻。。参数,使整个参数块在内存中连续,这在varargs函数的实现中很有用



此外,用于分配和取消分配堆栈空间的
addi
addiu
一样更好,因为这是指针算法(地址是无符号的),有符号整数溢出充其量是无趣的,最坏情况下是有害的(通过导致不相关的溢出异常).

这段代码包含一些错误,是什么让你认为它会出错?@Michael这道问题来自我的大学考试。完整的问题描述是“此代码包含一些违反某些MIPS呼叫约定的错误。请指出此代码违反MIPS呼叫约定?(被呼叫方的责任,呼叫方的责任,或两者兼而有之?)
func: addiu $sp,$sp,-8    
      sw $ra, 4($sp)    
      addi $a0,$a0,1    
      addi $a1,$a1,2 
      sw $a1, 0($sp)    # save a1 in stack before call
      jal foo           # this call effectively wipes out argument registers
      lw $a1, 0($sp)    # restore a1 from stack after call
      addi $a0,$v0,4    # here the function re-initializes $a0 from return value $v0
      add $v0,$a0,$a1   # now using re-initialized $a1 (ok)
      lw $ra,4($sp)    
      addiu $sp,$sp,8    
      jr $ra