CS641 MIPS Assembly Language Function Calling Examples

 

countstring1.s:   Count a string using simple stack frames (but not yet mips-gcc compliant). This program does follow the register conventions of pg. 118.

.text

# register usage:

# s0: pointer to string

        .globl  main

main:                    

       addi    $sp, $sp, -8 # claim 2 words

       sw      $ra, 4($sp)  # save ra

       sw      $s0, 0($sp)  # and s0

       la      $s0, msg     # load address of msg into a0

       move    $a0, $s0     # use a0 for arg

       jal     str_length   # takes str in a0, returns len in v0

       move    $a0, $v0

       ori     $v0,$0,1     # syscall 1 for print int with addr in a0

       syscall

       move    $a0, $s0     # reload str addr from $s0 (preserved across call)

       ori     $v0,$0,4     # syscall 4 for print string with addr in a0

       syscall

       lw      $s0, 0($sp)  # restore s0       

       lw      $ra, 4($sp)  # restore ra

       addi    $sp, $sp, 8  # pop frame

       jr      $ra          # return from main

 

# register usage:

# t0: pointer to string

# t1: count

# t2: current byte of string

# Note this function calls no functions itself, making it a “leaf”

# As a leaf, it doesn’t need to save and restore $ra

str_length:

      move     $t0, $a0      # point to string  <-- arg in a0

      li       $t1, 0        # count = 0

loop: lb       $t2, 0($t0)   # load byte of string

      beq      $t2, $0, done # check if byte = 0

      addi     $t1,$t1,1     # inc count

      addi     $t0, $t0, 1   # inc pointer

      j loop                 # loop back

done: move     $v0, $t1      # count to return  <--return val in v0

      jr       $ra           # return

 

.data

msg:    .asciiz "Hello, world!"

 

C program

char str2count[] = "abcdefg";

int main()

{

    printf("%d\n", str_length(str2count));

}

int str_length(char *p)

{

    int i = 0;

    for (; *p; p++)

        i++;

    return i;

}

Result of mips-gcc –S countstring2.c, converted to SPIM assembler: caller allocates space for arguments to call on stack, here 1 arg, but rounded up to 4. Caller puts the one arg in a0 (not on the stack, even though there is a spot reserved for it.) Callee puts it in the stack spot and then uses it from there.

# countstring2.s:  countstring using mips-gcc calling convention

.text

.globl  main

.globl  str_length

main:  

      addi    $sp, $sp, -32 # claim for $ra, $fp, $gp (2 wds), 4 args for str_length

      sw      $ra, 28($sp)  # save ra

      sw      $fp, 24($sp)  # save fp, then leave 8 bytes for $gp

      move    $fp, $sp      # fp for this function

      la      $a0, msg      # load address of msg into a0

      jal     str_length    # takes str in a0, returns len in v0

      #instead of printf--

      move    $a0, $v0

      ori     $v0,$0,1      # syscall 1 for print int with addr in a0

      syscall

      lw      $fp, 24($sp)  # restore fp

      lw      $ra, 28($sp)  # restore ra

      addi    $sp, $sp, 32  # pop frame

      jr      $ra           # return from main

 

# No registers in use except as temporaries (v0 here)

# stack usage:

# 24($fp): pointer to string  (arg 0)

# 8($fp): count (local var)

# Note this function calls no functions itself, making it a "leaf"

# As a leaf, it doesn't need to save and restore $ra, only $fp, space for $gp

# and locals, here count

 

str_length:

      addi    $sp, $sp, -24  # claim for $fp, $gp (2 wds), local count, pad

      sw      $fp, 20($sp)   # save caller's fp

      move    $fp, $sp       # establish fp for this function

      sw      $a0, 24($fp)   # save arg 0 to spot on stack

      sw      $0, 8($fp)     # init local var for count

 

loop: lw      $v0, 24($fp)   # point to string

      lb      $v0, 0($v0)    # load byte of string

      beq     $v0, $0, done  # check if byte = 0

      lw      $v0, 8($fp)    # count

      addiu   $v0, $v0,1     # inc count

      sw      $v0, 8($fp)    # store count

      lw      $v0, 24($fp)   # ptr

      addiu   $v0, $v0,1     # inc ptr

      sw      $v0, 24($fp)   # store ptr

      j loop                 # loop back

     

done: lw $v0, 8($fp)         # load count for return

      lw $fp, 16($fp)        # restore caller's fp

      addiu   $sp, $sp 24    # pop frame

      jr $ra                 # return

 

.data

msg:    .asciiz "Hello, world!"