【问题标题】:MIPS function call with more than four arguments具有四个以上参数的 MIPS 函数调用
【发布时间】:2011-01-18 22:08:02
【问题描述】:

我知道,每当我在 MIPS 中拥有一个具有四个以上参数的函数时,我都应该使用堆栈。然而,在下面的代码中,将第五个参数保存在sw $t0, 4($sp) 并执行jal sad,然后在sad 函数的开头,我再次调整堆栈指针以保存$sx 使用的寄存器呼叫者。我在这里做错了吗?

vbsme:  subu    $sp, $sp, 8     # create space on the stack pointer
    sw  $ra, 0($sp)     # save return address   

    li  $v0, 0          # reset $v0 
    li  $v1, 0          # reset $v1
    li  $s0, 1          # i(row) = 1 
    li  $s1, 1          # j(col) = 1
    lw  $s2, 0($a0)     # row size
    lw  $s3, 4($a0)     # col size
    mul     $s4, $s2, $s3       # row * col
    li  $s5, 0          # element = 0
loop:   bgeq    $s5, $s4, exit      # if element >= row * col then exit

    subi    $a3, $s0, 1     # 4th parameter: i-1
    subi    $t0, $s1, 1     
    sw  $t0, 4($sp)     # 5th parameter: j-1

    jal     sad         # calculate the sum of absolute difference using the frame starting from row a3 and col 4($sp)

    add $s6, $s0, $s1
    andi $s7, $s6, 1
if: bneq $s7, $zero, else
inif:   bge $s1, $s2, inelse
    addi $s1, $s1, 1
    j inif1
inelse: addi $s0, $s0, 2
inif1:  subi $s7, $s0, 1  
    beq $s7, $zero, loop_back
    subi $s0, $s0, 1
    j loop_back
else:   bge $s0, $s2, inelse1
    addi $s0, $s0, 1
    j inif2
inelse1:addi $s1, $s1, 2
inif2:  subi $s7, $s1, 1  
    beq $s7, $zero, loop_back
    subi $s1, $s1, 1
    j loop_back
loop_back: addi $s5, $s5, 1
       j loop
exit:   lw  $ra, 0($sp)     # restore return address
    addi    $sp, $sp, 8     # restore stack pointer   
    jr $ra              # return    

.globl  sad
sad:    subu $sp, $sp, 32       # allocate stack space for largest function
    sw $s7, 28($sp)         # save $s7 value    
    sw $s6, 24($sp)         # save $s6 value
    sw $s5, 20($sp)         # save $s5 value
    sw $s4, 16($sp)         # save $s4 value
    sw $s3, 12($sp)         # save $s3 value
    sw $s2, 8($sp)          # save $s2 value
    sw $s1, 4($sp)          # save $s1 value
    sw $s0, 0($sp)          # save $s0 value


    #some code to be filled later



    lw $s7, 28($sp)         # restore original value of $s7 for caller
    lw $s6, 24($sp)         # restore original value of $s6 for caller
    lw $s5, 20($sp)         # restore original value of $s5 for caller
    lw $s4, 16($sp)         # restore original value of $s4 for caller
    lw $s3, 12($sp)         # restore original value of $s3 for caller
    lw $s2, 8($sp)          # restore original value of $s2 for caller
    lw $s1, 4($sp)          # restore original value of $s1 for caller
    lw $s0, 0($sp)          # restore original value of $s0 for caller
    addiu $sp, $sp, 32      # restore the caller's stack pointer
    jr $ra              # return to caller's code

【问题讨论】:

  • 我看不出标题与问题的关系。
  • 确实如此,我在问如何获得函数 sad 中的第五个参数

标签: mips


【解决方案1】:

gcc 就是这样做的。有关更多信息,您(可以)应该阅读 Mips ABI。有些事情可能会有所不同。

http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf

按照惯例,第五个参数应该放在堆栈的第五个字上。

所以你应该

sad:
    sub $sp,$sp,24 #24 byte stack frame
    ... some code ...
    #Convention indicates to store $a0..$a3 in A..D (see below)
    sw $a0,0(sp)
    sw $a1,4(sp)
    sw $a2,8(sp)
    sw $a3,12(sp)

    #Get the 5th argument
    lw $t0,40($sp) #40 : 24 + 16

要在堆栈中存储第 5 个参数,您应该知道:

如果 vbsme 将调用另一个函数,则应保存堆栈的底部 4 个字,以便被调用者在那里存储参数值。如果传递的参数超过 4 个,则应为每个参数保存一个额外的单词。

vbsme's stack frame bottom part (Argument building area)

    |    ...       |
    ---------------
    |   5th arg    |  <---- sw      $t5,16($sp)     
    ---------------
    |     D        |
    ---------------
    |     C        |
    ---------------
    |     B        |
    ---------------
    |     A        |
    ---------------  <--sp (of vbsme stack frame)

另外,$ra 寄存器应该保存在栈顶,因为它的寄存器是 31。

vbsme:  
     subu    $sp, $sp, 20+N # 20: space for 5 arguments, 
                            #N space for other stuff (ra,$tx, etc)


     #Set arguments (assumes 5th parameter value is in register $t5)
     subi    $a3, $s0, 1     # 4th parameter: i-1
     sw      $t5,16($sp)     #

    ...
 .end

回应

Why is it that you do: 
lw $t0,40($sp)
to get the 5th argument, why did you add 24 to 16? when you do
sub $sp,$sp,24 
don't you already move
the sp 24 place?

是的,$sp + 24 指向调用者堆栈的底部。然而,这不是我放置第五个论点的地方。第五个参数放在调用者堆栈的第五个字上,这就是我添加 16 的原因。

【讨论】:

  • 你为什么这样做:lw $t0,40($sp) #40 : 24 + 16 得到第5个参数,你为什么要加24到16?当你做 sub $sp,$sp,24 你不是已经移动了 sp 24 的地方吗?
  • 为什么我还需要将 $a0 - $a4 保存到堆栈中?
  • 被调用者将参数存储在堆栈中的约定。 GCC 在没有优化的情况下以这种方式生成程序集,但使用 -01 从寄存器访问参数
  • 您还在 vbsme 中添加了注释:#N 空间用于其他内容(ra、$sx 等)调用者不应该保存 $sx 寄存器对吗?它应该保存 $tx 寄存器......这是我假设的错字吗?
  • 当我保存 $ra 时,我只会在循环结束时使用它,对吗?不是在日航之后?
猜你喜欢
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-01
  • 2012-06-17
  • 2013-09-27
  • 2016-06-30
  • 2013-06-13
相关资源
最近更新 更多