1

我正在尝试让函数 vbsme 调用另一个名为 sad 的函数...关于保存寄存器和返回地址的以下过程是否正确?调用者应该保存寄存器 $t0-$t7,但我应该在哪里以及如何做呢?

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
4

2 回答 2

2

$sx 寄存器保证在函数调用中保持不变,因此它的被调用者(sum 函数)负责保存它们,只有当它要改变它们的值时。

另一方面,$tx 寄存器不能保证在函数调用中保持不变,因此调用者 (vbsme) 有责任保存它们。

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

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

堆栈中的空间通过减去指向堆栈底部的 $sp 寄存器来节省。在您的函数代码之前,您应该为该函数创建堆栈,在必要时保存所有调用者保存的寄存器、返回地址和全局指针寄存器

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 (临时)寄存器来代替。

于 2010-02-19T17:49:49.403 回答
1

亚历山大,

What Tom said is pretty much correct the important thing to note with doing programming in assembly is everything is by convention. While in MIPS the common convention is what Tom noted it is not the only convention. For instance if you are using macro's (which if you are going to be writing more than 1 or 2 functions in assembly it is a much easier to use macros) then you can define your calling convention in the macro. The easiest way to do this is instead of having the callee save the stack is to have the caller save the stack. This is less efficient because sometimes (perhaps many times) unused registers will be saved, however it will save you a lot of heartache because your convention is applied consistently.

Caller Stack Save:

    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)

Function call

    jal my_func

Caller Stack Restore

    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

Your function:

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

As I said the best way to apply this convention is to use macros. I did a project in SPIM (which you may being using or you may not be) for a class. As part of the project we wrote a macro engine (it does other cool stuff as well) for SPIM you can get it here: http://github.com/timtadh/mpp I would also recommend checking out http://github.com/timtadh/jist which is a toy operating system written on top of SPIM. It will give you a sense of how to use the macro engine.

cheers

于 2010-02-22T04:38:45.960 回答