0
votes

recently I hustled through the wonderful world of mips assembly :D I actually wrote a find minimum function and it actually worked. Compiled everything with QtSPIM and I'm very happy.

Well the main is actually some code snippet I got from a lecture in university.. I just wrote the function itself. So here is my question. I think I figured out how the stackpointer works with adressing and so one. In this example we're using the adress of the sp -4 bytes to save this in the $ra register. Why are we using the stack itself for this? I could just use the $ra adress itself or not? Or is this actually a habit we should create, I guess maybe later it could be helpfull to safe the return adresses on a stack, but maybe you could explain this to me in more detail.

As always I highly appreciate every help. Thank you guys :)

minimum:




    lw      $v0, 0($a0)
    add     $t0, $zero, $zero                           # i = 0


for:
    bge     $t0, $a1, endfor                            # if(i>=n) goto endfor
    sll     $t1, $t0, 2                                 # $t1 = 4*i
    add     $t1, $a0, $t1                               # $t1 = a + 4*i = &a[i]
    lw      $t1, 0($t1)                                 # $t1 = a[i]

    slt     $t2, $t1, $v0                               #set t2 = 1 if (t1<v0)
    beq     $t2, 1, setnewmin                           # if t2 == 1 go to label setnewmin
    addi    $t0, $t0, 1
    j       for

setnewmin:
    move    $v0, $t1                                    #store new new minimum in v0 
    addi    $t0, $t0, 1                                 # i++
    j       for

endfor: 



    jr      $ra                                         #go back to main


# Some Parameters
#


    .data
array: .word 5, 17, 3, 22, 120, -412, 14, 254, 1000, 2, 7, 1001
n:     .word 12


#
# main
#a

    .text
    .globl main

main:
    addi    $sp, $sp, -4        # save return adress
    sw  $ra, 0($sp)

    la  $a0, array      # array adress
    lw  $a1, n        

    jal minimum

    move    $s1, $v0

    move    $a0, $s1

    li  $v0, 1
    syscall


    lw  $ra, 0($sp)
    addi    $sp, $sp, 4
    jr  $ra

#
# end main
#
1
It's common practice on processors that store the return address in a register for the lowest level functions that do not call other functions to just use the register that contains the return address. This dates back to IBM 360, which uses a caller provided save area instead of a stack.rcgldr
@rcgldr: Wasn't using a link register instead of having a call instruction write an address to memory a RISC feature? It means only load/store instructions have to write to memory, call / ret equivalents only touch registers. (I think MIPS even allows 2 regs to be asynchronously clobbered at any time, I assume for interrupt-return info so even interrupts don't have to be microcoded). This is much more RISCy than having a non-stack "save area", unless you meant that IBM360 used a link reg and the callee stored it in the save area manually.Peter Cordes
IBM 360 used BALR - branch and link register instead of a stack based call instruction.markgz
@PeterCordes - as commented by markgz, IBM 360 BALR puts the return address in a user specified register, and branches to an address in another user specified register. The calling convention is that R13 points to the caller supplied save area, R14 gets the return address, R15 is the branch target address.rcgldr

1 Answers

3
votes

The $ra register holds the return address of the current function. The return address specifies the address of the instruction at which execution should continue when the current function returns.

If the current function itself (main) needs to call another function (minimum), the jal instruction will overwrite the contents of $ra. If that happened, main wouldn't be able to return to the correct address. Therefore, it's necessary for main to save a temporary copy of $ra so that it can be restored when required. The following instructions save a copy of the return address on the stack:

addi    $sp, $sp, -4        # save return adress
sw  $ra, 0($sp)

The following instructions restore that copy just before returning from main:

lw  $ra, 0($sp)
addi    $sp, $sp, 4

The jr $ra instruction returns to the function that called main (also used at the end of minimum for the same purpose).

Note that minimum doesn't need to save a copy of $ra because it doesn't contain any instruction that destroys its value.