Computer Systems Fundamentals


C Function with No Parameters or Return Value
#include <stdio.h>

void f(void);

int main(void) {
    printf("calling function f\n");
    f();
    printf("back from function f\n");
    return 0;
}

void f(void) {
    printf("in function f\n");
}
simple example of returning from a function loops because main does not save return address
main:
    la   $a0, string0   # printf("calling function f\n");
    li   $v0, 4
    syscall

    jal  f              # set $ra to following address

    la   $a0, string1   # printf("back from function f\n");
    li   $v0, 4
    syscall

    li   $v0, 0         # fails because $ra changes since main called
    jr   $ra            # return from function main


f:
    la   $a0, string2   # printf("in function f\n");
    li   $v0, 4
    syscall
    jr   $ra            # return from function f


    .data
string0:
    .asciiz "calling function f\n"
string1:
    .asciiz "back from function f\n"
string2:
    .asciiz "in function f\n"
simple example of placing return address on stack note stack grows down
main:
    addi $sp, $sp, -4    # move stack pointer down to make room
    sw   $ra, 0($sp)    # save $ra on $stack

    la   $a0, string0   # printf("calling function f\n");
    li   $v0, 4
    syscall

    jal  f              # set $ra to following address

    la   $a0, string1   # printf("back from function f\n");
    li   $v0, 4
    syscall

    lw   $ra, 0($sp)    # recover $ra from $stack
    addi $sp, $sp, 4    # move stack pointer back to what it was

    li   $v0, 0         # return 0 from function main
    jr   $ra            #


f:
    la   $a0, string2   # printf("in function f\n");
    li   $v0, 4
    syscall
    jr   $ra            # return from function f


    .data
string0:
    .asciiz "calling function f\n"
string1:
    .asciiz "back from function f\n"
string2:
    .asciiz "in function f\n"
simple example of placing return address on stack begin, end, push pop are pseudo-instructions provided by mipsy but not spim
main:
    push $ra            # save $ra on $stack

    la   $a0, string0   # printf("calling function f\n");
    li   $v0, 4
    syscall

    jal  f              # set $ra to following address

    la   $a0, string1   # printf("back from function f\n");
    li   $v0, 4
    syscall

    pop $ra             # recover $ra from $stack

    li   $v0, 0         # return 0 from function main
    jr   $ra            #


# f is a leaf function so it doesn't need an epilogue or prologue
f:
    la   $a0, string2   # printf("in function f\n");
    li   $v0, 4
    syscall
    jr   $ra            # return from function f


    .data
string0:
    .asciiz "calling function f\n"
string1:
    .asciiz "back from function f\n"
string2:
    .asciiz "in function f\n"
simple example of returning a value from a function
#include <stdio.h>

int answer(void);

int main(void) {
    int a = answer();
    printf("%d\n", a);
    return 0;
}

int answer(void) {
    return 42;
}
simple example of returning a value from a function note storing of return address $ra
code for function main
main:
    begin               # move frame pointer
    push  $ra           # save $ra onto stack

    jal   answer        # call answer(), return value will be in $v0

    move  $a0, $v0      # printf("%d", a);
    li    $v0, 1        #
    syscall             #

    li    $a0, '\n'     # printf("%c", '\n');
    li    $v0, 11       #
    syscall             #

    pop   $ra           # recover $ra from stack
    end                 # move frame pointer back

    li    $v0, 0        # return
    jr    $ra           #


# code for function answer
answer:
    li   $v0, 42        # return 42
    jr   $ra            #

A simple program that calls a function with 3 arguments and prints its return value
main:
    #int main(void) {
    #    z = sum(x,y,30);
    #    
    #    printf("%d\n",z);
    #    return 0;
    #}
    push $ra     # save $ra

    lw $a0, x    # set up arguments in a registers
    lw $a1, y
    li $a2, 30
    jal sum      # sum(x,y,30);
    
    sw $v0, z
    
    li $v0, 1    # printf("%d",z);
    lw $a0, z
    syscall
    
    li $v0, 11   # printf("\n")
    li $a0, '\n'
    syscall        


    li $v0, 0
    
    pop $ra      # restore $ra 
    jr $ra       # return 0

sum:
    #int sum(int a, int b, int c) {
    #    return a+b+c;
    #}
    #a $a0, b $a1, c $a2
    add $v0, $a0, $a1   #$v0 = a + b
    add $v0, $v0, $a2   #$v0 = a + b + c
    
    jr $ra


.data
x:
    .word 5
y: 
    .word 7
z: 
    .space 4

Example of using an $s register and saving it and restoring it from the stack
main:
    #int main()
    #{
    #   int max;
    #   print("Enter +ve integer: ");
    #   scanf("%d", &max); ****
    #   int tmp = sumTo(max);
    #   printf("Sum 1..%d = %d\n", max, tmp); ***
    #   return 0;
    #}
    #Prolog
    push $ra            
    push $s0
	
    li $v0, 4               # print("Enter +ve integer: ");
    la $a0, ask
    syscall
	
    li $v0, 5               # scanf("%d", &max); 
    syscall
    move $s0, $v0           # I need max after the function call
                            # I need to store it safely
	
    move $a0, $v0
    jal sumTo               # sumTo(max);
	
    move $t0, $v0           # tmp = sumTo(max)
	
    li $v0, 4               # printf("Sum 1..")
    la $a0, out1
    syscall
	
    li $v0, 1               # printf(max)
    move $a0, $s0
    syscall
	
    li $v0, 4               # printf(" = ")
    la $a0, out2
    syscall
	
    li $v0, 1               # printf(tmp)
    move $a0, $t0
    syscall
	
    li $v0, 11              # printf("\n")
    li $a0, '\n'
    syscall
	
    li  $v0, 0
    #epilog
    pop $s0
    pop $ra
    jr $ra
   
#$v0       $a0   
#int sumTo(int n)
#{
#   int sum = 0;
#   for (int i = 1; i <= n; i++) 
#       sum += i;
#   return sum;
#}
    
sumTo:
    li $t0, 0                   # int sum = 0;
    li $t1, 1                   # int i = 1;
sumTo_for:
    bgt	$t1, $a0, sumTo_for_end # if i > n goto sumTo_for_end
    add $t0, $t0, $t1           # sum = sum + i
    addi $t1, $t1, 1            # i++
    j sumTo_for
sumTo_for_end:  
    move $v0, $t0
    jr $ra
    

    .data
ask:
    .asciiz "Enter +ve integer: "
out1:
    .asciiz "Sum 1.."
out2:
    .asciiz " = "
    

An example of a recursive function
main:
    #int main()
    #{
    #   int max;
    #   print("Enter +ve integer: ");
    #   scanf("%d", &max); ****
    #   int tmp = sumTo(max);
    #   printf("Sum 1..%d = %d\n", max, tmp); ***
    #   return 0;
    #}
    #prolog
	push $ra            
    push $s0
	
    li $v0, 4               # print("Enter +ve integer: ");
    la $a0, ask
    syscall
	
    li $v0, 5               # scanf("%d", &max); 
    syscall
    move $s0, $v0           # I need max after the function call
                            # I need to store it safely
	
    move $a0, $v0
    jal sumTo               # sumTo(max);
	
    move $t0, $v0           # tmp = sumTo(max)
	
    li $v0, 4               # printf("Sum 1..")
    la $a0, out1
    syscall
	
    li $v0, 1               # printf(max)
    move $a0, $s0
    syscall
	
    li $v0, 4               # printf(" = ")
    la $a0, out2
    syscall
	
    li $v0, 1               # printf(tmp)
    move $a0, $t0
    syscall
	
    li $v0, 11              # printf("\n")
    li $a0, '\n'
    syscall
	
    li  $v0, 0
    #epilog
    pop $s0
    pop $ra
    jr $ra 
   
#$v0       $a0   
#int sumTo(int n) {          
# if(n == 0){
#     return 0;
# } 
# tmp = sumTo(n-1)           
# return n + tmp;            
#}   
sumTo:
    push $ra
    push $s0

    move $s0, $a0            # $s0 = n
    bnez $s0, else           # if(n != 0) goto else
    li $v0, 0                # returnValue = 0
    j epilog
else:    
    
    addi $a0, $s0, -1        # $a0 = n - 1
    jal sumTo                # $v0 = sumTo(n-1)
    add $v0, $s0, $v0        # returnValue = n + $v0

epilog:   
    pop $s0
    pop $ra
    jr $ra
    

    .data
ask:
    .asciiz "Enter +ve integer: "
out1:
    .asciiz "Sum 1.."
out2:
    .asciiz " = "
    

Example of passing an array into a function
main:
    #prolog
    push $ra

    la  $a0, array          #v0 = sumOf(array,10);
    li  $a1, 10
    jal sumOf

    move $a0, $v0           #printf("%d",v0);
    li $v0, 1
    syscall
                

    li $v0, 0
    #epilog
    pop $ra
    jr $ra

#int sumOf(int a[], int n)
#{
#   int i;  int sum = 0;
#   for (i = 0; i < n; i++) sum += a[i];
#   return sum;
#}

#int sumOf(int a[], int n)
#{
#   int i = 0;  
#   int sum = 0;
#   
# for:
#   if i >= n goto end_for
#   sum = sum + a[i];
#   i = i + 1;
#   goto for
# end_for
#   return sum;
#}

sumOf:
    #prolog
    push $ra
 
    li      $t0, 0              #$t0 is i; i = 0
    li      $t1, 0              #$t0 is sum; sum = 0;
    li      $t2, 4              #$t0 is sizeof(int)
for:
    bge     $t0, $a1, end_for   #if i >= n goto end_for
    
    mul     $t3, $t0, $t2       #offset = i * 4
    
    add     $t4, $a0, $t3       #t4 = address of a + offset
    lw      $v0, ($t4)          #$v0 = a[i]
    add     $t1, $t1, $v0       #sum = sum + a[i]
    addi    $t0, $t0, 1         # i = i + 1
    j       for                 #goto for
end_for:
    move    $v0, $t1            #set return value
    #epilog
    pop     $ra
    jr      $ra
    
   .data
array:
    .word 5, 4, 7, 6, 8, 9, 1, 2, 3, 0  

A recursive array function
main:
    #prolog
    push $ra

    la  $a0, array          #v0 = sumOf(array,0,9);
    li  $a1, 0
    li  $a2, 9
    jal sumOf

    move $a0, $v0           #printf("%d",v0);
    li $v0, 1
    syscall
                
    li $v0, 0
    #epilog
    pop $ra
    jr	$ra


#int sumOf(int a[], int lo, int hi)
#{
#   if (lo > hi)                         
#      return 0;                             
#                                         
#   else
#      return a[lo] + sumOf(a,lo+1,hi);   
#}

sumOf:
    #prolog
    push    $ra
    push    $s0
    push    $s1
    push    $s2

    ble     $a1, $a2 else       #if (lo <= hi) goto else
    li      $v0, 0
    j       end
else:
    move    $s0, $a0
    move    $s1, $a1
    move    $s2, $a2

    addi    $a1, $a1, 1         #a1 = lo+1
    jal     sumOf
    li      $t0, 4
    mul     $t0, $t0, $s1       #offset = lo * 4
    add     $t0, $t0, $s0       #offset = offset + a                
    lw      $t1, ($t0)          #a[lo]
    add     $v0, $v0, $t1       #returnValue = returnValue + a[lo]
end:
    #epilog
    pop     $s2
    pop     $s1
    pop     $s0
    pop     $ra
    jr      $ra
    
    .data
array:
    .word 5, 4, 7, 6, 8, 9, 1, 2, 3, 0   
store first 10 squares into an array which is a local variable then print them from array
#include <stdio.h>

int main(void) {
    int squares[10];
    int i = 0;
    while (i < 10) {
        squares[i] = i * i;
        i++;
    }
    i = 0;
    while (i < 10) {
        printf("%d", squares[i]);
        printf("%c",'\n');
        i++;
    }
    return 0;
}
i in register $t0 registers $t1, and $t2, used to hold temporary results
main:
    begin               # move frame pointer
    addi $sp, $sp, -40  # move stack pointer down to make room to store array numbers on stack

    li   $t0, 0         # i = 0
loop0:
    bge  $t0, 10, end0  # while (i < 10) {

    mul  $t1, $t0, 4    #    calculate &numbers[i]
    add  $t2, $t1, $sp  #
    mul  $t3, $t0, $t0  #    calculate i * i
    sw   $t3, ($t2)     #    store in array

    addi $t0, $t0, 1    #    i++;
    b    loop0          # }
end0:

    li   $t0, 0         # i = 0
loop1:
    bge  $t0, 10, end1  # while (i < 10) {

    mul  $t1, $t0, 4
    add  $t2, $t1, $sp  #   calculate &numbers[i]

    lw   $a0, ($t2)     #   load numbers[i] into $a0
    li   $v0, 1         #   printf("%d", numbers[i])
    syscall             #

    li   $a0, '\n'      #   printf("%c", '\n');
    li   $v0, 11        #
    syscall             #

    addi $t0, $t0, 1    #   i++
    b    loop1          # }
end1:

    addi $sp, $sp, 40   # move stack pointer back up to what it was when main called
    end                 # move frame pointer back

    li   $v0, 0         # return 0
    jr   $ra            #
int main(void) { printf("Welcome"); int x = 99; f1(); printf("Goodbye"); printf("%d",x); return 0; }
void f1(void) { printf("Hi there\n"); f2(); printf("It is me again\n"); }
void f2(void){ printf("I love chips\n"); }


This example uses the push and pop pseudo instructions that only work in mipsy
.data
main_str1: .asciiz "Welcome\n"

main_str2: .asciiz "Goodbye\n"

f1_str1: .asciiz "Hi there\n"

f1_str2: .asciiz "It is me again\n"

f2_str1: .asciiz "I love chips\n"


.text

main:
    begin          # sets the frame pointer
    push $ra       # store $ra on stack
    push $s0       # store $s0 on stack
    
    li $v0, 4      # printf("Welcome");
    la $a0, main_str1
    syscall
    
    li $s0, 99     # we use an s (safe) register to make sure
                   # our value 99 still exists after our function call
    
    jal  f1        # f1()

    li $v0, 4      # printf("Goodbye");
    la $a0, main_str2
    syscall
    
    li $v0, 1      # printf("%d",x)
    move $a0, $s0
    syscall
    
    li $v0, 0      # set return value to 0 
    
    pop $s0        # store $s0 on stack
    pop $ra        # restore $ra from stack   
    end            # restores the frame pointer
    jr $ra         # return            

 
f1:
    begin
    push $ra       # store $ra on stack
    push $s0 
    
    li $s0, 42     # If we had not pushed $s0 onto the stack
    #etc           # This would overwrite the value of $s0 for 
                   # for the main function 
    
    li $v0, 4      # printf("Hi there\n");
    la $a0, f1_str1
    syscall
    
    jal f2
    
    li $v0, 4      # printf("It is me again\n");
    la $a0, f1_str2
    syscall
    
    
    
    pop $s0
    pop $ra
    end
    jr $ra
 
f2:
    begin
    push $ra       # store $ra on stack
    push $s0
    
    li $v0, 4      # printf("I love chips\n");
    la $a0, f2_str1
    syscall
    
    li $s0, 10     # If we had not pushed $s0 onto the stack
                   # This would overwrite the value of $s0 for 
                   # for the main function
    #etc
    pop $s0
    pop $ra
    end
    jr $ra