2010-02-19 95 views
1

我想让函数vbsme调用另一个名为sad ...的函数,下面的程序是否正确地保存了寄存器和返回地址?调用者应该保存注册$ t0- $ t7,但是在哪里以及如何执行该操作?函数里面的MIPS函数

vbsme: li $v0, 0 # reset $v0 
    li $v1, 0 # reset $v1 
    li $t0, 1 # i(row) = 1 
    li $t1, 1 # j(col) = 1 
    lw $t2, 0($a0) # row size 
    lw $t3, 4($a0) # col size 
    mul $t4, $t2, $t3 # row * col 
    li $t5, 0 # element = 0 
    loop: bgeq $t5, $t4, exit # if element >= row * col then exit 

    addi $sp, $sp, -16 # create space on the stack pointer 
    sw $ra, -12($sp) # save return address 
    sw $s6, -8($sp) # save return address 
    sw $s7, -4($sp) # save return address 
    subi $s7, $t0, 1 # 1st parameter: i-1 
    subi $s6, $t1, 1 # 2nd parameter: j-1 
    jal sad # calculate the sum of absolute difference using the frame starting from row a0 and col a1 
    lw $ra, -12($sp) # restore return address 
    lw $s6, -8($sp) 
    lw $s7, -4($sp) 
    addi $sp, $sp, 16 # restore stack pointer 
    jr $ra 
+0

我重新写我的回答,$ S0 .. $ S7被调用函数保存寄存器 – Tom 2010-02-19 18:13:18

回答

2

$ SX寄存器保证是不变翻过函数调用,因此它被调用者(SUM函数)负责保存它们的,只有当它要改变自己的价值。

另一方面,$ tx寄存器不保证在函数调用中保持不变,所以它的调用者(vbsme)负责保存它们。

您应该在被调用堆栈中保存$ sx。

所以当你开始编码sum函数时,你应该节省堆栈空间 如果你想保存n个寄存器,那么保存n * 4。

通过减去指向堆栈底部的$ sp寄存器来保存堆栈中的空间。你的函数代码之前,您应该创建堆栈该功能,保存所有来电者保存的寄存器,返回时neccesary

sum: 
     #stack frame creation. Caller registers saved, 
     # return address and frame pointer 

     subu $sp,$sp,36 #Save space in the stack for registers $s0, $s7 + $ra 
     sw $ra,32($sp) 
     sw $s0,0($sp) 
     sw $s1,4($sp) 
     #and so on. Note that also you should save the $ra register only if you are 
     # going to call another function 

     #do something with $sx 

     #stack frame destruction 
     #restore $sx and $ra registers 
     lw $ra,32($sp) 
     lw $s0,0($sp) 
     lw $s1,4($sp) 
     ... 
     lw $s7,28($sp) 

     jr $ra 

顺便说地址和全局指针寄存器,按照惯例,寄存器$ A0,$ A3应将参数保存到您要调用的函数中。另外请注意,因为您使用$ s0,$ s7寄存器,所以您必须做一些额外的工作。公约说,如果你不使用它们,那么你不应该保存它们,所以也许你可以使用$ tx(临时)寄存器来代替它们。

+0

不应调用者保存寄存器$ T0- $ T7,而不是$的寄存器? – aherlambang 2010-02-19 17:51:48

+0

vbsme这里是sum函数的调用者吧? – aherlambang 2010-02-19 17:52:20

+0

vbsme调用者,总结调用者 – Tom 2010-02-19 17:55:37

1

亚历山大,

什么汤姆说是非常正确的,在装配做节目要注意,重要的是一切都按照约定。在MIPS中,通用约定是Tom指出它不是唯一的约定。例如,如果您正在使用宏(如果您要在汇编中编写超过1或2个函数,则使用宏更容易),那么您可以在宏中定义调用约定。最简单的方法是让被调用者保存堆栈,而不是让调用者保存堆栈。这效率较低,因为有时(可能多次)未使用的寄存器将被保存,但由于您的约定一致地应用,它会为您节省很多心痛。

调用程序堆栈节省:

sw $fp 0($sp) # save the old frame pointer 
    addu $fp $sp $0 # move the frame pointer to point at top of frame 
    subu $sp $sp 44 # move the stack pointer down 44 
    sw $fp 40($sp) # save the old stack pointer 
    sw $ra 36($sp) # save the return address 
    sw $s0 32($sp) # save registers $s0 - $s7 
    sw $s1 28($sp) 
    sw $s2 24($sp) 
    sw $s3 20($sp) 
    sw $s4 16($sp) 
    sw $s5 12($sp) 
    sw $s6 8($sp) 
    sw $s7 4($sp) 

函数调用

jal my_func 

调用程序堆栈恢复

subu $sp $fp 44 # move the stack pointer to the orginal unmodified bottom 
    lw $ra 36($sp) # load the return address 
    lw $s0 32($sp) # load registers $s0 - $s7 
    lw $s1 28($sp) 
    lw $s2 24($sp) 
    lw $s3 20($sp) 
    lw $s4 16($sp) 
    lw $s5 12($sp) 
    lw $s6 8($sp) 
    lw $s7 4($sp) 
    lw $fp 44($sp) # load the old frame pointer 
    lw $sp 40($sp) # load the old stack pointer 

您的功能:

my_func: 
    do some stuff 
    jr $ra    # return to the previous function 

正如我所说的应用这种约定的最好方法是使用宏。我在SPIM中做了一个项目(你可能正在使用,或者你可能不会这样做)。作为项目的一部分,我们为SPIM编写了一个宏引擎(它也有其他很酷的东西),你可以在这里得到它: http://github.com/timtadh/mpp 我也建议检查http://github.com/timtadh/jist这是一个写在SPIM之上的玩具操作系统。它会给你一个如何使用宏引擎的感觉。

欢呼