Lecture08 assembly language

Preview:

Citation preview

COMPUTER ORGANIZATION

AND ASSEMBLY LANGUAGE

Lecture 8

Functions and Recursive function calls in

MIPS

What have we learned

So far

Write any program in MIPS

Today

More Examples of Function Calls

2

Steps for Making a Function Call

1) Save necessary values onto stack

2) Assign argument(s), if any

3) jal call

4) Restore values from stack

3

Structure of a Function

1) Save necessary values onto stack

2) Function body

3) Set return value(s) in $v0 (and $v1), if any

4) Restore values from stack

5) jr $ra

4

Example Function

sumSquare:

addi $sp,$sp,-8 # space on stack

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

sw $a1, 0($sp) # save y

add $a1,$a0,$zero # mult(x,x)

jal mult # call mult

lw $a1, 0($sp) # restore y

add $v0,$v0,$a1 # mult()+y

lw $ra, 4($sp) # get ret addr

addi $sp,$sp,8 # restore stack

jr $ra

mult: ...

int sumSquare(int x, int y) {

return mult(x,x)+ y;

}

“push”

“pop”

5

Rules for Function Calls

Called with a jal instruction, returns with a jr $ra

Accepts up to 4 arguments in $a0, $a1, $a2 and $a3

Return value is always in $v0 (and if necessary in

$v1)

Must follow register conventions

even in functions that only you will call!

6

Other Registers

$at: may be used by the assembler at any time;

unsafe to use

$k0-$k1: may be used by the OS at any time; unsafe

to use

$gp, $fp: don’t worry about them

Feel free to read up on $gp and $fp in Appendix A, but you

can write perfectly good MIPS code without them.

7

Basic Structure of a Function

entry_label:addi $sp,$sp, -framesizesw $ra, framesize-4($sp) # save $rasave other regs if need be

...

restore other regs if need belw $ra, framesize-4($sp) # restore $raaddi $sp,$sp, framesizejr $ra

Epilogue

Prologue

Body (call other functions…)

ra

memory

8

Register Conventions – Saved Registers

$0: No Change. Always 0.

$s0-$s7: Restore if you change. Very important, that’s

why they’re called saved registers. If the callee changes

these in any way, it must restore the original values before

returning.

$sp: Restore if you change. The stack pointer must point

to the same place before and after the jal call, or else the

caller won’t be able to restore values from the stack.

HINT -- All saved registers start with S!

9

Register Conventions – Volatile

Registers

$ra: Can Change. The jal call itself will change this

register. Caller needs to save on stack if nested call.

$v0-$v1: Can Change. These will contain the new

returned values.

$a0-$a3: Can change. These are volatile argument

registers. Caller needs to save if they’ll need them after the

call.

$t0-$t9: Can change. That’s why they’re called

temporary: any procedure may change them at any time.

Caller needs to save if they’ll need them afterwards.

10

Register Conventions

What do these conventions mean?

If function R calls function E, then function R must

save any temporary registers that it may be using

onto the stack before making a jal call.

Function E must save any S (saved) registers it

intends to use before garbling up their values

Remember: CalleR/calleE need to save only

temporary/saved registers they are using, not all

registers.

11

Requirements for Functions

Pass arguments to the function

$a0, $a1, $a2, $a3

Get results from the function

$v0, $v1

Can call from anywhere

jal

Can always return back

jr

Nested and Recursive Functions

Save $ra on stack

Saving and Restoring Registers

Register Conventions

Functions with more than 4 parameters

Pass them on the stack

12

Nested Procedures

Leaf procedures do not call other procedures.

What happens to return addresses with nested procedures?

int rt_1 (int i) {

if (i == 0) return 0;

elsereturn rt_2(i-1);

}

caller: jal rt_1

next: . . .

rt_1: bne $a0, $zero, to_2add $v0, $zero, $zerojr $ra

to_2: addi $a0, $a0, -1jal rt_2jr $ra

rt_2: . . .

13

Nested Procedures Outcome

caller: jal rt_1next: . . .

rt_1: bne $a0, $zero, to_2add $v0, $zero, $zerojr $ra

to_2: addi $a0, $a0, -1jal rt_2jr $ra

rt_2: . . .

• On the call to rt_1, the return address (next in the caller routine) gets stored in $ra. What happens to the value in $ra (when i != 0) when rt_1 makes a call to rt_2?

int rt_1 (int i)

{

if (i == 0)

return 0;

else

return rt_2(i-1);

}

14

caller rt addr

caller rt addr

Saving the Return Address, Part

1Nested procedures (i passed in $a0, return value in $v0)

high addr

$sp

low addr

$a0 value

$rart_2

old TOS

rt_1: bne $a0, $zero, to_2

add $v0, $zero, $zero

jr $ra

to_2: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

addi $a0, $a0, -1

jal rt_2

rt_2: lw $a0, 0($sp)

lw $ra, 4($sp)

addi $sp, $sp, 8

jr $ra

• Save the return address (and arguments) on the stack

int rt_1 (int i)

{

if (i == 0)

return 0;

else

return rt_2(i-1);

}

$a0

$rt_2 $a0 value

$a0 value $a0 value - 1

15

Compiling a Recursive Procedure

Calculating factorial:int fact (int n) {if (n < 1) return 1;else return (n * fact (n-1));

}

Recursive procedure (one that calls itself!)

fact (0) = 1

fact (1) = 1 * 1 = 1

fact (2) = 2 * 1 * 1 = 2

fact (3) = 3 * 2 * 1 * 1 = 6

fact (4) = 4 * 3 * 2 * 1 * 1 = 24

. . .

Assume n is passed in $a0; result returned in $v0

16

Compiling a Recursive Procedure

fact: addi $sp, $sp, -8 #adjust stack pointer

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

sw $a0, 0($sp) #save argument n

slt $t0, $a0, 1 #test for n < 1

beq $t0, $zero, L1 #if n >=1, go to L1

addi $v0, $zero, 1 #else return 1 in $v0

addi $sp, $sp, 8 #adjust stack pointer

jr $ra #return to caller

L1: addi $a0, $a0, -1 #n >=1, so decrement n

jal fact #call fact with (n-1)

#this is where fact returns

bk_f: lw $a0, 0($sp) #restore argument n

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

addi $sp, $sp, 8 #adjust stack pointer

mul $v0, $a0, $v0 #$v0 = n * fact(n-1)

jr $ra #return to caller

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

17

1

caller rt addr

caller rt addr

A Look at the Stack for $a0 =

2 $sp

$ra

$a0

$v0

$a0 = 2

2

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

fact: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

slt $t0, $a0, 1

beq $t0, $zero, L1

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

L1: addi $a0, $a0, -1

jal fact

bk_f: lw $a0, 0($sp)

lw $ra, 4($sp)

addi $sp, $sp, 8

mul $v0, $a0, $v0

jr $ra

18

1

caller rt addr

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

$a0 = 2

bk_f

old TOS

• Stack state after execution of first encounter with the jalinstruction (second call to fact routine with $a0 now holding 1)– saved return address to caller

routine (i.e., location in the main routine where first call to fact is made) on the stack

– saved original value of $a0 on the stack

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

19

1

bk_f

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

$a0 = 1

0

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

caller rt addr

$a0 = 2fact: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

slt $t0, $a0, 1

beq $t0, $zero, L1

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

L1: addi $a0, $a0, -1

jal fact

bk_f: lw $a0, 0($sp)

lw $ra, 4($sp)

addi $sp, $sp, 8

mul $v0, $a0, $v0

jr $ra

20

caller rt addr

A Look at the Stack for $a0 =

2

$ra

$a0

$v0

$a0 = 2

0

bk_f

old TOS

$sp$a0 = 1

bk_f

bk_f

• Stack state after execution of second encounter with the jal instruction (third call to fact routine with $a0 now holding 0)– saved return address of

instruction in caller routine (instruction after jal) on the stack

– saved previous value of $a0on the stack

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

21

1

bk_f

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

$a0 = 1

0

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

caller rt addr

$a0 = 2fact: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

slt $t0, $a0, 1

beq $t0, $zero, L1

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

L1: addi $a0, $a0, -1

jal fact

bk_f: lw $a0, 0($sp)

lw $ra, 4($sp)

addi $sp, $sp, 8

mul $v0, $a0, $v0

jr $ra

bk_f

$a0 = 0

22

1

bk_f

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

$a0 = 1

0

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

caller rt addr

$a0 = 2 • Stack state after execution of first encounter with the first jr instruction ($v0initialized to 1)– stack pointer updated to

point to third call to fact

23

1

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

0

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

caller rt addr

$a0 = 2fact: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

slt $t0, $a0, 1

beq $t0, $zero, L1

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

L1: addi $a0, $a0, -1

jal fact

bk_f: lw $a0, 0($sp)

lw $ra, 4($sp)

addi $sp, $sp, 8

mul $v0, $a0, $v0

jr $ra

bk_f

$a0 = 1

1

1*1 = 1

24

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

caller rt addr

$a0 = 2

1

1

• Stack state after execution of first encounter with the second jr instruction (return from fact routine after updating $v0 to 1 * 1)

– return address to caller routine (bk_f in fact routine) restored to $ra from the stack

– previous value of $a0restored from the stack

– stack pointer updated to point to second call to fact

25

1

A Look at the Stack for $a0 =

2

$sp

$ra

$a0

$v0

1

bk_f

old TOS

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

caller rt addr

$a0 = 2fact: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

slt $t0, $a0, 1

beq $t0, $zero, L1

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

L1: addi $a0, $a0, -1

jal fact

bk_f: lw $a0, 0($sp)

lw $ra, 4($sp)

addi $sp, $sp, 8

mul $v0, $a0, $v0

jr $ra

2

2*1 = 2

caller rt addr

26

A Look at the Stack for $a0 =

2 $sp

$ra

$a0

$v0

old TOS

2

2

caller rt addr

• Stack state after execution of second encounter with the second jr instruction (return from fact routine after updating $v0 to 1 * 1 * 2)

– return address to caller routine (main routine) restored to $rafrom the stack

– original value of $a0 restored from the stack

– stack pointer updated to point to first call to fact

int fact (int n)

{

if (n < 1)

return 1;

else

return (n * fact (n-1));

}

27

Summary

Requirements for functions

Register Conventions

Nested function calls

Recursive function calls

28

Recommended