0% found this document useful (0 votes)
49 views9 pages

Mips Functions Notes

The document describes how function calls work in MIPS, including how arguments are passed into functions stored in registers, how the function address is stored in $ra to return to the caller, and how local variables and preserved registers can be stored on the stack. It provides examples of different types of functions and function calls in MIPS assembly language to illustrate parameter passing and returning values. The stack is used to allocate space for local variables and preserved registers by growing the stack pointer down and restoring it before returning.

Uploaded by

Albert Yan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views9 pages

Mips Functions Notes

The document describes how function calls work in MIPS, including how arguments are passed into functions stored in registers, how the function address is stored in $ra to return to the caller, and how local variables and preserved registers can be stored on the stack. It provides examples of different types of functions and function calls in MIPS assembly language to illustrate parameter passing and returning values. The stack is used to allocate space for local variables and preserved registers by growing the stack pointer down and restoring it before returning.

Uploaded by

Albert Yan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

MIPS Functions Function Calls

Simple view of function calls:

When we call a function: • load argument values into $a0, $a1, $a2, $a3.
• jal function set $ra to PC+4 and jumps to function
• the arguments are evaluated and set up for function • function puts return value in $v0
• control is transferred to the code for the function • returns to caller using jr $ra

• local variables are created


• the function code is executed in this environment
• the return value is set up
• control transfers back to where the function was called from
• the caller receives the return value

1 2

Function with No Parameters or Return Value Function with a Return Value but No Parameters

• jal hello sets $ra to address of following instruction and


transfers execution to hello
• jr $ra transfers execution to the address in $ra • by convention function return value is passed back in $v0

int main(void) { main: int main(void) { main:


hello(); ... int a = answer(); ...
return 0; jal hello printf("%d\n", a); jal answer
} ... return 0; move $a0, $v0
hello: } li $v0, 1
void hello(void) { la $a0, string syscall
printf("hi\n"); li $v0, 4 int answer(void) { ...
} syscall return 42; answer:
jr $ra } li $v0, 42
.data jr $ra
string:
.asciiz "hi\n"
3 4
Function with a Return Value and Parameters Function calling another function - DO NOT DO THIS

• by convention first 4 function parameters passed in $a0 $a1 $a2 $a3


• a function that calls another function must save $ra
• if there are more parameters they are passed on the stack
• the jr $ra in main below will fail because jal hello changed $ra
int main(void) { main:
int main(void) { main:
int a = product(6, 7); ...
hello(); jal hello
printf("%d\n", a); li $a0, 6
return 0; li $v0, 0
return 0; li $a1, 7
} jr $ra # THIS WILL FAIL
} jal product
hello:
move $a0, $v0
void hello(void) { la $a0, string
int product(int x, int y) { li $v0, 1
printf("hi\n"); li $v0, 4
return x * y; syscall
} syscall
} ...
jr $ra
product:
.data
mul $v0, $a0, $a1
string: .asciiz "hi\n"
jr $ra

5 6

Simple Function Call Example - C Simple Function Call Example - broken MIPS

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


li $v0, 4
syscall
void f(void);
jal f # set $ra to following address
int main(void) {
la $a0, string1 # printf("back from function f\n");
printf("calling function f\n");
li $v0, 4
f();
syscall
printf("back from function f\n");
li $v0, 0 # fails because $ra changes since main called
return 0;
jr $ra # return from function main
}
f:
void f(void) {
la $a0, string2 # printf("in function f\n");
printf("in function f\n");
li $v0, 4
}
source code for call_return.c syscall
jr $ra # return from function f
.data
source code for call_return.broken.s

7 8
Stack - Where it is in Memory Stack - Allocating Space

Data associated with a function call placed on the stack:


• $sp (stack pointer) initialized by operating system
• always 4-byte aligned (divisible by 4)
• points at currently used (4-byte) word
• grows downward
• a function can do this to allocate 40 bytes:
sub $sp, $sp, 40 # move stack pointer down

• a function must leave $sp at original value


• so if you allocated 40 bytes, before return (jr $ra)
add $sp, $sp, 40 # move stack pointer back

9 10

Stack - Using stack to Save/Restore registers Stack - Growing & Shrinking

Figure 1: image
f:
sub $sp, $sp, 12 # allocate 12 bytes How stack changes as functions are called and return:
sw $ra, 8($sp) # save $ra on $stack
sw $s1, 4($sp) # save $s1 on $stack
sw $s0, 0($sp) # save $s0 on $stack

...

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


lw $s1, 4($sp) # restore $s1 from $stack
lw $ra, 8($sp) # restore $ra from $stack
add $sp, $sp, 12 # move stack pointer back
jr $ra # return

11 12
Function calling another function - How to Do It Simple Function Call Example - correct MIPS

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


• a function that calls another function must save $ra li $v0, 4
syscall
main:
jal f # set $ra to following address
sub $sp, $sp, 4 # move stack pointer down
la $a0, string1 # printf("back from function f\n");
# to allocate 4 bytes
li $v0, 4
sw $ra, 0($sp) # save $ra on $stack
syscall
lw $ra, 0($sp) # recover $ra from $stack
jal hello # call hello
addi $sp, $sp, 4 # move stack pointer back to what it was
li $v0, 0 # return 0 from function main
lw $ra, 0($sp) # recover $ra from $stack
jr $ra #
add $sp, $sp, 4 # move stack pointer back up
f:
# to what it was when main called
la $a0, string2 # printf("in function f\n");
li $v0, 0 # return 0
li $v0, 4
jr $ra #
syscall
jr $ra # return from function f
source code for call_return.s
13 14

MIPS Register usage conventions MIPS Register usage conventions - not covered in COMP1521

• a0..a3 contain first 4 arguments • floating point registers used to pass/return float/doubles
• $v0 contains return value • similar conventions for saving floating point registers
• $ra contains return address • stack used to pass arguments after first 4
• if function changes $sp, $fp, $s0..$s8 it restores their value • stack used to pass arguments which do not fit in register
• callers assume $sp, $fp, $s0..$s8 unchanged by call (jal) • stack used to return values which do not fit in register
• a function may destroy the value of other registers e.g. $t0..$t9 • for example C argument or return value can be a struct, wh ich is any
• callers must assume value in e.g. $t0..$t9 changed by call (jal) number of bytes

15 16
Example - Returning a Value - C Example - Returning a Value - MIPS
main:
addi $sp, $sp, -4 # move stack pointer down to make room
sw $ra, 0($sp) # save $ra on $stack
int answer(void); jal answer # call answer, return value will be in $v0
int main(void) { move $a0, $v0 # printf("%d", a);
int a = answer(); li $v0, 1
printf("%d\n", a); syscall
return 0; li $a0, '\n' # printf("%c", '\n');
} li $v0, 11
int answer(void) { syscall
return 42; lw $ra, 0($sp) # recover $ra from $stack
} addi $sp, $sp, 4 # move stack pointer back up to what it was when
source code for return_answer.c jr $ra #
answer: # code for function answer
li $v0, 42 #
jr $ra # return from answer
source code for return_answer.s
17 18

Example - Argument & Return - C Example - Argument & Return - MIPS (main)

void two(int i);


int main(void) { main:
two(1); addi $sp, $sp, -4 # move stack pointer down to make room
} sw $ra, 0($sp) # save $ra on $stack
void two(int i) { li $a0, 1 # two(1);
if (i < 1000000) { jal two
two(2 * i); lw $ra, 0($sp) # recover $ra from $stack
} addi $sp, $sp, 4 # move stack pointer back up to what it was whe
printf("%d\n", i); jr $ra # return from function main
source code for two_powerful.s
}
source code for two_powerful.c

19 20
Example - Argument & Return - MIPS (two) Example - More complex Calls - C
two:
addi $sp, $sp, -8 # move stack pointer down to make room
sw $ra, 4($sp) # save $ra on $stack int main(void) {
sw $a0, 0($sp) # save $a0 on $stack int z = sum_product(10, 12);
bge $a0, 1000000, print printf("%d\n", z);
mul $a0, $a0, 2 # restore $a0 from $stack return 0;
jal two }
print: int sum_product(int a, int b) {
lw $a0, 0($sp) # restore $a0 from $stack int p = product(6, 7);
li $v0, 1 # printf("%d"); return p + a + b;
syscall }
li $a0, '\n' # printf("%c", '\n'); int product(int x, int y) {
li $v0, 11 return x * y;
syscall }
source code for more_calls.c
lw $ra, 4($sp) # restore $ra from $stack
addi $sp, $sp, 8 # move stack pointer back up to what it was when main called
jr $ra # return from two 21 22
source code for two_powerful.s

Example - more complex Calls - MIPS (main) Example - more complex Calls - MIPS (sum_product)
main: sum_product:
addi $sp, $sp, -4 # move stack pointer down to make room addi $sp, $sp, -12 # move stack pointer down to make room
sw $ra, 0($sp) # save $ra on $stack sw $ra, 8($sp) # save $ra on $stack
li $a0, 10 # sum_product(10, 12); sw $a1, 4($sp) # save $a1 on $stack
li $a1, 12 sw $a0, 0($sp) # save $a0 on $stack
jal sum_product li $a0, 6 # product(6, 7);
move $a0, $v0 # printf("%d", z); li $a1, 7
li $v0, 1 jal product
syscall lw $a1, 4($sp) # restore $a1 from $stack
li $a0, '\n' # printf("%c", '\n'); lw $a0, 0($sp) # restore $a0 from $stack
li $v0, 11 add $v0, $v0, $a0 # add a and b to value returned in $v0
syscall add $v0, $v0, $a1 # and put result in $v0 to be returned
lw $ra, 0($sp) # recover $ra from $stack lw $ra, 8($sp) # restore $ra from $stack
addi $sp, $sp, 4 # move stack pointer back up to what it was when main addi called$sp, $sp, 12 # move stack pointer back up to what it was whe
li $v0, 0 # return 0 from function main jr $ra # return from sum_product
jr $ra # return from function main source code for more_calls.s

source code for more_calls.s


23 24
Example - more complex Calls - MIPS (product) Example - strlen using array - C

C Simple C
int main(void) { int main(void) {
• a function which doesn’t call other functions is called a leaf function int i = my_strlen("Hello"); int i = my_strlen("Hello");
• its code can be simpler printf("%d\n", i); printf("%d\n", i);
return 0; return 0;
int product(int x, int y) {
} }
return x * y;
int my_strlen(char *s) { int my_strlen(char *s) {
}
source code for more_calls.c
int length = 0; int length = 0;
while (s[length] != 0) { loop:
product: # product doesn't call other functions
length++; if (s[length] == 0) goto end;
# so it doesn't need to save any registers
} length++;
mul $v0, $a0, $a1 # return argument * argument 2
return length; goto loop;
jr $ra #
source code for more_calls.s
}
source code for strlen_array.c
end:
return length;
}
source code for strlen_array.simple.c

25 26

Example - pointer - C Example - pointer - MIPS


main:
la $t0, answer # p = &answer;
lw $t1, ($t0) # i = *p;
int main(void) { move $a0, $t1 # printf("%d\n", i);
int i; li $v0, 1
int *p; syscall
p = &answer; li $a0, '\n' # printf("%c", '\n');
i = *p; li $v0, 11
printf("%d\n", i); // prints 42 syscall
*p = 27; li $t2, 27 # *p = 27;
printf("%d\n", answer); // prints 27 sw $t2, ($t0) #
return 0; lw $a0, answer # printf("%d\n", answer);
} li $v0, 1
source code for pointer.c
syscall
li $a0, '\n' # printf("%c", '\n');
li $v0, 11
27 syscall 28
Example - strlen using pointer - C Example - strlen using pointer - MIPS (my_strlen)

int main(void) { la $a0, string # my_strlen("Hello");


int i = my_strlen("Hello"); jal my_strlen
printf("%d\n", i); move $a0, $v0 # printf("%d", i);
return 0; li $v0, 1
} syscall
int my_strlen(char *s) { li $a0, '\n' # printf("%c", '\n');
int length = 0; li $v0, 11
while (s[length] != 0) { syscall
length++; lw $ra, 0($sp) # recover $ra from $stack
} addi $sp, $sp, 4 # move stack pointer back up to what it was when ma
return length; li $v0, 0 # return 0 from function main
} jr $ra #
source code for strlen_array.c source code for strlen_array.s

29 30

Storing A Local Variables On the Stack Example - strlen using pointer - C

• some local (function) variables must be stored on stack


int main(void) {
• e.g. variables such as arrays and structs
int i = my_strlen("Hello");
int main(void) { main: printf("%d\n", i);
int squares[10]; sub $sp, $sp, 40 return 0;
int i = 0; li $t0, 0 }
while (i < 10) { loop0: int my_strlen(char *s) {
squares[i] = i * i; mul $t1, $t0, 4 int length = 0;
i++; add $t2, $t1, $sp while (s[length] != 0) {
} mul $t3, $t0, $t0 length++;
source code for squares.c
sw $t3, ($t2) }
add $t0, $t0, 1 return length;
b loop0 }
source code for strlen_array.c
end0:
source code for squares.s

31 32
What is a Frame Pointer Example of Growing Stack Breaking Function Return

void f(int a) { f:
int length; sub $sp, $sp, 4
• frame pointer $fp is a second register pointing to stack scanf("%d", &length); sw $ra, 0($sp)
int array[length]; li $v0, 5
• by convention set to point at start of stack frame
// ... more code ... syscall
• provides a fixed point during function code execution printf("%d\n", a); # allocate space for
• useful for functions which grow stack (change $sp) during execution }
source code for frame_pointer.c
# array on stack
mul $t0, $v0, 4
• makes it easier for debuggers to forensically analyze stack sub $sp, $sp, $t0
• e.g if you want to print stack backtrace after error # ... more code ...
# breaks because $sp
• frame pointer is optional (in COMP1521 and generally)
# has changed
• often omitted when fast execution or small code a priority lw $ra, 0($sp)
add $sp, $sp, 4
jr $ra
source code for frame_pointer.broken.s

33 34

Example of Frame Pointer Use

void f(int a) { f:
int length; sub $sp, $sp, 8
scanf("%d", &length); sw $fp, 4($sp)
int array[length]; sw $ra, 0($sp)
// ... more code ... add $fp, $sp, 8
printf("%d\n", a); li $v0, 5
}
source code for frame_pointer.c
syscall
mul $t0, $v0, 4
sub $sp, $sp, $t0
# ... more code ...
lw $ra, -4($fp)
move $sp, $fp
lw $fp, 0($fp)
jr $ra
source code for frame_pointer.s

35

You might also like