MIPS: relevant use for a stack pointer ($sp) and the stack

前端 未结 2 1965
夕颜
夕颜 2020-12-13 05:21

Currently I\'m studying for my computer organization midterm, and I\'m trying to fully understand the stack pointer and the stack. I know these following facts that surround

2条回答
  •  萌比男神i
    2020-12-13 06:16

    The MIPS calling convention requires first four function parameters to be in registers a0 through a3 and the rest, if there are more, on the stack. What's more, it also requires the function caller to allocate four slots on the stack for the first four parameters, despite those being passed in the registers.

    So, if you want to access parameter five (and further parameters), you need to use sp. If the function in turn calls other functions and uses its parameters after the calls, it will need to store a0 through a3 in those four slots on the stack to avoid them being lost/overwritten. Again, you use sp to write these registers to the stack.

    If your function has local variables and can't keep all of them in registers (like when it can't keep a0 through a3 when it calls other functions), it will have to use the on-stack space for those local variables, which again necessitates the use of sp.

    For example, if you had this:

    int tst5(int x1, int x2, int x3, int x4, int x5)
    {
      return x1 + x2 + x3 + x4 + x5;
    }
    

    its disassembly would be something like:

    tst5:
            lw      $2,16($sp) # r2 = x5; 4 slots are skipped
            addu    $4,$4,$5   # x1 += x2
            addu    $4,$4,$6   # x1 += x3
            addu    $4,$4,$7   # x1 += x4
            j       $31        # return
            addu    $2,$4,$2   # r2 += x1
    

    See, sp is used to access x5.

    And then if you have code something like this:

    int binary(int a, int b)
    {
      return a + b;
    }
    
    void stk(void)
    {
      binary(binary(binary(1, 2), binary(3, 4)), binary(binary(5, 6), binary(7, 8)));
    }
    

    this is what it looks in disassembly after compilation:

    binary:
            j       $31                     # return
            addu    $2,$4,$5                # r2 = a + b
    
    stk:
            subu    $sp,$sp,32              # allocate space for local vars & 4 slots
            li      $4,0x00000001           # 1
            li      $5,0x00000002           # 2
            sw      $31,24($sp)             # store return address on stack
            sw      $17,20($sp)             # preserve r17 on stack
            jal     binary                  # call binary(1,2)
            sw      $16,16($sp)             # preserve r16 on stack
    
            li      $4,0x00000003           # 3
            li      $5,0x00000004           # 4
            jal     binary                  # call binary(3,4)
            move    $16,$2                  # r16 = binary(1,2)
    
            move    $4,$16                  # r4 = binary(1,2)
            jal     binary                  # call binary(binary(1,2), binary(3,4))
            move    $5,$2                   # r5 = binary(3,4)
    
            li      $4,0x00000005           # 5
            li      $5,0x00000006           # 6
            jal     binary                  # call binary(5,6)
            move    $17,$2                  # r17 = binary(binary(1,2), binary(3,4))
    
            li      $4,0x00000007           # 7
            li      $5,0x00000008           # 8
            jal     binary                  # call binary(7,8)
            move    $16,$2                  # r16 = binary(5,6)
    
            move    $4,$16                  # r4 = binary(5,6)
            jal     binary                  # call binary(binary(5,6), binary(7,8))
            move    $5,$2                   # r5 = binary(7,8)
    
            move    $4,$17                  # r4 = binary(binary(1,2), binary(3,4))
            jal     binary                  # call binary(binary(binary(1,2), binary(3,4)), binary(binary(5,6), binary(7,8)))
            move    $5,$2                   # r5 = binary(binary(5,6), binary(7,8))
    
            lw      $31,24($sp)             # restore return address from stack
            lw      $17,20($sp)             # restore r17 from stack
            lw      $16,16($sp)             # restore r16 from stack
            addu    $sp,$sp,32              # remove local vars and 4 slots
            j       $31                     # return
            nop
    

    I hope I've annotated the code without making mistakes.

    So, note that the compiler chooses to use r16 and r17 in the function but preserves them on the stack. Since the function calls another one, it also needs to preserve its return address on the stack instead of simply keeping it in r31.

    PS Remember that all branch/jump instructions on MIPS effectively execute the immediately following instruction before actually transferring control to a new location. This might be confusing.

提交回复
热议问题