/
Procedures and Stacks Don Porter Procedures and Stacks Don Porter

Procedures and Stacks Don Porter - PowerPoint Presentation

calandra-battersby
calandra-battersby . @calandra-battersby
Follow
354 views
Uploaded On 2019-03-16

Procedures and Stacks Don Porter - PPT Presentation

1 Today Procedures What are procedures Why use them How is callreturn implemented in assembly Recursion Stacks Push and pop How useful for implementing procedures 2 What are Procedures ID: 756899

addi stack save sqr stack addi sqr save restore return procedure callee frame caller registers call procedures local int arguments proc1 variables

Share:

Link:

Embed:

Download Presentation from below link

Download Presentation The PPT/PDF document "Procedures and Stacks Don Porter" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.


Presentation Transcript

Slide1

Procedures and Stacks

Don Porter

1Slide2

Today

ProceduresWhat are procedures?Why use them?How is call/return implemented in assembly?Recursion

Stacks

Push and pop

How useful for implementing procedures?

2Slide3

What are Procedures?

Also called:functionsmethodssubroutines

Key Idea:

main routine

M calls

a procedure

P

P does some work, then returns to Mexecution in M picks up where left offi.e., the instruction in M right after the one that called P

3Slide4

Why Use Procedures?

Readabilitydivide up long program into smaller proceduresReusabilitycall same procedure from many parts of code

programmers can use each others’ code

Parameterizability

same function can be called with different arguments/parameters at runtime

Polymorphism (in OOP)

in C++/Java, behavior can be determined at runtime as opposed to compile time

Any other reason…?4Slide5

Why Use Procedures?

Examples:

Reusable code fragments (modular design)

clear_screen

();

… # code to draw a bunch of lines

clear_screen

();

Parameterized functions (variable behaviors)

line(x1, y1, x2, y2, color);

line(x2,y2,x3,y3, color);

# Draw a polygon

for (i=0; i<N-1; i++) line(x[i],y[i],x[i+1],y[i+1],color);line(x[i],y[i],x[0],y[0],color);

5Slide6

Another Reason: Scope of Variables

Local scope (Independence)

int

x = 9;

int

fee(

int

x) {

return x+x-1;

}

int

foo(

int

i) { int x = 0; while (i > 0) { x = x + fee(i); i = i

- 1;

}

return x;}main() { fee(foo(x));}

These are different

x

s

This is yet another

x

Removes need

to keep track

of all of the

variable names!

6Slide7

Using Procedures

A “

calling

program (Caller) must:

Provide procedure “parameters” / “arguments”

put the arguments in a place where the procedure can access them

Transfer control to the procedure

jump to it

A

called

procedure (Callee) must:

Acquire the resources needed to perform the functionPerform the functionPlace results in a place where the Caller can find themReturn control back to the CallerSolution (at least a partial one):Allocate registers for these specific functions7Slide8

MIPS Register Usage

Conventions designate registers for procedure arguments ($4-$7) and return values ($2-$3).

The ISA designates a

linkage register

for calling procedures ($31)

allows

Callee

to go back to Caller once done

Transfer control to

Callee

using the

jal instruction

Return to Caller with the jr $31 or jr $ra instruction

8Slide9

And It

“Sort Of” Works

Example:

.data

x: .word 9

.text

main:

lw

$a0, x

jal

fee

...

fee: add $v0,$a0,$a0 addi $v0,$v0,-1 jr $ra

(fee

computes

2*x - 1)Works for special caseswhere the Callee is a “LEAF” functionCallee doesn’t call anybody, and needs few resourcesBut there are lots of unaddressed issues:how can fee call another?

how can we have more than 4 arguments?where are local variables stored?

Let’s consider the worst case: recursionCallee is also a Caller…

9Caller

CalleeSlide10

Writing Procedures

int

sqr

(

int

x) {

  if (x > 1)

x =

sqr

(x-1)+x+x-1;

  return x;

}

main()

{ sqr(10);}

sqr

(10) =

sqr(9)+10+10-1 = 100sqr(9) = sqr(8)+9+9-1 = 81sqr

(8) = sqr

(7)+8+8-1 = 64

sqr(7) = sqr(6)+7+7-1 = 49sqr(6) = sqr(5)+6+6-1 = 36sqr(5) = sqr(4)+5+5-1 = 25sqr(4) = sqr(3)+4+4-1 = 16sqr(3) = sqr(2)+3+3-1 = 9sqr(2) = sqr(1)+2+2-1 = 4sqr(1) = 1sqr(0) = 0

How do we go about writing callable procedures? We’d like to support not only LEAF procedures, but also procedures that call other procedures, ad infinitum (e.g. a recursive function).10Slide11

Procedure Linkage: First Try

sqr

:

slti

$t0,$a0,2

beq

$t0,$0,then #!(x<2)

add $v0,$0,$a0

j

rtn

then:

add $t0,$0,$a0addi $a0,$a0,-1

jal sqradd $v0,$v0,$t0add $v0,$v0,$t0addi $v0,$v0,-1rtn:jr $raOOPS!

MIPS Convention:

pass 1

st arg x in $a0 save return addr in $ra

return result in $v0

use temp registers

for scratch workint sqr(int x) {   if (x > 1) x = sqr(x-1)+x+x-1;  return x; }main(){

sqr(10);}Caller

Callee/Caller

$t0 is clobbered on successive calls.

We also clobber our return address, so there’

s no way back!

Will saving

x

in some register or at some fixed location in memory help?

11Slide12

A Procedure

’s Storage Needs

Basic Overhead for Procedures/Functions:

Caller

sets up ARGUMENTs for

callee

f(

x,y,z

)

or even...

sin(

a+b

)Caller invokes Callee while saving theReturn Address to get backCallee saves stuff that Caller expectsto remain unchangedCallee executes Callee passes results back to Caller.Local variables of

Callee

:

...{ int x, y; ... x ... y ...;

}

Each of these is specific to a

“particular” invocation or activation of the Callee. Collectively, the arguments passed in, the return address, and the callee’s local variables are its activation record, or call frame.

In C it’

s the caller’s job to evaluate its arguments as expressions, and pass the resulting values to the

callee

… Therefore, the CALLEE has to save arguments if it wants access to them after calling some other procedure, because they might not be around in any variable, to look up later.

12Slide13

Lives of Activation Records

int

sqr

(

int

x) {

  if (x > 1)

x =

sqr

(x-1)+x+x-1;

  return x;

}

sqr(3)

TIME

A procedure call creates a new activation record. Caller’

s record is preserved because we’ll need it when call finally returns.

Return to previous activation record when procedure finishes, permanently discarding activation record created by call we are returning from.

sqr(3)

sqr(2)

sqr(3)

sqr(2)

Where do we store activation records?

sqr(3)sqr(2)sqr(1)sqr(3)13Slide14

We Need Dynamic Storage!

What we need is a SCRATCH memory for holding temporary variables. We’

d like for this memory to grow and shrink as needed. And, we’d like it to have an easy management policy.

Some interesting properties of stacks:

SMALL OVERHEAD. Only the top is directly visible, the so-called

top-of-stack

Add things by PUSHING new values on top.

Remove things by POPPING off values.

One possibility is a

STACK

A last-in-first-out (LIFO)

data structure.

14Slide15

MIPS Stack Convention

CONVENTIONS:

• Waste a register for the Stack Pointer

($

sp

= $29).

• Stack grows DOWN (towards lower addresses) on pushes and allocates

• $

sp

points to the

TOP

*used* location.

• Place stack far away

from our programand its data

Other possible implementations include: 1) stacks that grow “UP” 2) SP points to first UNUSED locationHigher addresses

Lower addresses

$sp

Humm… Why

is that the TOP

of the stack?

Reserved

text

segment

(Program)

stack

segment

8000000

16

Data

10000000

16

00400000

16

10008000

16

15Slide16

Stack Management Primitives

ALLOCATE k

:

reserve k WORDS of stack

Reg

[SP] =

Reg[SP] - 4*k

DEALLOCATE k

:

release k WORDS of stack

Reg

[SP] = Reg[SP] + 4*k

PUSH rx: push Reg[x] onto stackReg[SP] = Reg[SP] - 4Mem[Reg[SP]] = Reg[x]POP rx: pop the value on the top of the stack into Reg[x] Reg[x] = Mem[Reg[SP]] Reg[SP] = Reg[SP] + 4;addi $sp,$sp,-4sw $rx, 0($sp)

lw $rx, 0($sp)

addi $sp,$sp,4

addi $sp,$sp,-4*kaddi $sp,$sp,4*k

16Slide17

Solving Procedure Linkage

“Problems”

In case you forgot, a reminder of our problems

We need a way to pass arguments into procedures

Procedures need storage for their LOCAL variables

Procedures need to call other procedures

Procedures might call themselves (Recursion)

But first: Let’s

waste

some more registers:

$30 = $

fp (frame pointer)points to the start of

callee’s activation record on the stackwe also use it to access extra args (>4)$29 = $sp (stack pointer, points to TOP of stack)points to the and of callee’s activation record on the stackTogether: $29 and $30 are bookends to activation record$31 = $ra (return address back to caller)17Slide18

More MIPS Procedure Conventions

What needs to be saved?CHOICE 1… anything that a

Callee

touches

except the return value registers

CHOICE 2… Give the

Callee

access to everythingCaller saves those registers it expects to remain unchanged

CHOICE 3… Something in between

Give the

Callee

some

scratch” registers to play withIf the Caller cares about these, it must preserve them ($t registers)

Give the Caller some registers that the Callee won’t clobberIf the Callee touches them, it must restore them ($s registers) MIPS designers chose #318Slide19

Stack Frame or Activation Record

19

FP:

SP:

Saved regs

Local variables

Args > 4

(unused)

The STACK FRAME contains storage for the CALLER’

s volatile state that it wants preserved after the invocation of CALLEEs.

In addition, the CALLEE will use the stack for the following:

1) Accessing the arguments that the

CALLER passes to it

(specifically, the 5

th

and greater)

2) Saving non-temporary registers that

it wishes to modify

3) Accessing its own local variables

The boundary between stack frames falls at the first word of state saved by the CALLEE, and just after the extra arguments (>4, if used) passed in from the CALLER. The FRAME POINTER keeps track of this boundary between stack frames.

It is possible to use only the SP to access a stack frame, but offsets may change due to ALLOCATEs and DEALLOCATEs. For convenience a $

fp

is used to provide CONSTANT offsets to local variables and argumentsCALLEE’sStack Frame

CALLER’sStack FrameSlide20

Procedure Stack Usage

ADDITIONAL space must be allocated in the stack frame for:

Any SAVED registers the procedure uses ($s0-$s7)

Any TEMPORARY registers that the procedure wants preserved

IF it calls other procedures ($t0-$t9)

Any LOCAL variables declared within the procedure

Other TEMP space IF the procedure runs out of registers (RARE)

Enough

outgoing

arguments to satisfy the worse case

ARGUMENT SPILL

of ANY procedure it calls.

(SPILL is the number of arguments greater than 4).

Each procedure has keep track of how many SAVED and TEMPORARY registers are on the stack in order to calculate the offsets to LOCAL VARIABLES.

20Slide21

More MIPS Register Usage

The registers $s0-$s7, $sp

, $

ra

, $

gp

, $

fp

, and the stack above the memory above the stack pointer must be preserved by the CALLEE

The CALLEE is free to use $t0-$t9, $a0-$a3, and $v0-$v1, and the memory below the stack pointer.

No

user

” program can use $k0-$k1, or $at

21Slide22

Stack Snap Shot: A typical procedure

A typical “activation record” or “stack frame”

save $

ra

and $

fp

first

save values of “saved regs

” modified by this

proc

e.g.: $s0, $s1, $s2, $s3

save values of “temp

regs

” that must survive calls to other procs

from this proce.g.: $t0, $t1should be saved immediately before calling other proc; restored immediately afterany local variables needed (that are not in regs) reside on the stacke.g.: locals var1 … varnany spillover args for calling other procs [in reverse order]e.g.: arg[4], arg

[5]

why reverse order?

$ra

$

fp

$s0$s1

$s2$s3$t0

$t1local var1…

local varnarg[5]arg[4]

$sp

$fp22Slide23

Stack Snap Shot:

Caller + Callee

proc

A calls

proc

B

B has less stuff that needs to be saved on stack

Can you tell the number of

args

for B?

NOPE!

Can you tell the max number of

args

needed by any procedure called by A?

Yes, 6Where in CALLEE’s stack frame might one find CALLER’s $fp?At -4($fp)CALLER A’SFRAME$ra

$

fp

$s0

$s1

$s2

$s3

$t0$t1local var1

…local varn

Arg[5]Arg[4]$ra

$fplocal var1local var2Arg[6]

Arg[5]Arg[4]

CALLEE B’SFRAME

$sp (after call)

$sp (prior to call)

CALLER’

s $fp

CALLEE’

s $fp

23Slide24

Back to Reality

Now let’

s make our example work, using a

minimal stack frame

int

sqr

(

int

x) {

  if (x > 1)

x =

sqr

(x-1)+x+x-1;

  return x; }main(){ sqr(10);} sqr: addi $sp,$sp,-8 sw $ra,4($sp

)

sw $a0,0($sp) slti $t0,$a0,2beq $t0,$0,thenadd $v0,$0,$a0j rtn

then:

addi $a0,$a0,-1

jal sqrlw $a0,0($sp)add $v0,$v0,$a0add $v0,$v0,$a0addi $v0,$v0,-1rtn:lw $ra,4($sp) addi $sp,$sp,8jr $ra

ALLOCATE minimum stack frame. With room for the return address and the passed in argument.

Save registers that must survive the call.

Pass arguments

DEALLOCATE

stack frame.

A: Don’

t have local

variables or spilled

args.

Q: Why didn’

t we save and update $fp?

Restore saved registers.

24Slide25

Testing Reality

’s BoundariesNow let

s take a look at the active stack frames at some point during the procedure

s execution.

sqr

:

addi

$sp,$sp,-8

sw

$ra,4($

sp) sw

$a0,0($sp) slti $t0,$a0,2beq $t0,$0,thenmove $v0,$a0j rtn then:addi $a0,$a0,-1jal sqrlw $a0,0($sp)add $v0,$v0,$a0add $v0,$v0,$a0addi $v0,$v0,-1rtn:lw $ra,4($sp) addi $sp,$sp,8

jr

$

ra$ra = 0x00400018

$a0 = 10

10

$ra = 0x00400074

$a0 = 910$ra = 0x00400074$a0 = 810

PC

Return Address to original caller

$sp

25Slide26

Procedure Linkage is Nontrivial

The details can be overwhelming. How do we manage this complexity?

Abstraction: High-level languages hide the details

There are great many implementation choices:

which variables are saved

who saves them

where are arguments stored?

Solution: CONTRACTS!

Caller and

Callee

must agree on the details

26Slide27

Procedure Linkage: Caller Contract

The CALLER will:

Save all temp registers that it wants

to survive subsequent calls in its

stack frame

(t0-$t9, $a0-$a3, and $v0-$v1)

Pass the first 4 arguments in registers

$a0-$a3, and save subsequent arguments on stack, in *reverse* order.

Why?

Call procedure, using a

jal

instruction

(places return address in $

ra

).

Access procedure’

s return values in $v0-$v1

27Slide28

Our running example is a CALLER. Let

’s make sure it obeys its contractual obligations

sqr

:

addiu

$sp,$sp,-8

sw

$ra,4($

sp

)

sw

$a0,0($sp)

slti $t0,$a0,2 beq $t0,$0,then add $v0,$0,$a0 j rtnthen: addi $a0,$a0,-1 jal sqr lw $a0,0($sp) add $v0,$v0,$a0 add $v0,$v0,$a0 addi $v0,$v0,-1rtn:

lw

$ra,4($sp) addiu $sp,$sp,8 jr $ra

Code Lawyer

int sqr(int x) {

  if (x > 1)

x = sqr(x-1)+x+x-1;  return x; }28Slide29

Procedure Linkage:

Callee Contract

If needed the CALLEE will:

1) Allocate a stack frame with space for saved

registers, local variables, and spilled

args

2) Save any

preserved

registers used:

($

ra

, $

sp

, $

fp

, $

gp

, $s0-$s7)

3) If CALLEE has local variables -or- needs access to

args

on the stack, save CALLER’s frame pointer and set $fp to 1st entry of CALLEE’s stack 4) EXECUTE procedure 5) Place return values in $v0-$v1 6) Restore saved registers 7) Fix $sp to its original value 8) Return to CALLER with jr $ra29Slide30

Our running example is also a CALLEE. Are these contractual obligations satisfied?

More Legalese

sqr

:

addiu

$sp,$sp,-8

sw

$ra,4($

sp

)

sw

$a0,0($

sp) slti

$t0,$a0,2

beq $t0,$0,then add $v0,$0,$a0 j rtnthen: addi $a0,$a0,-1 jal

sqr

lw $a0,0($sp) add $v0,$v0,$a0 add $v0,$v0,$a0 addi $v0,$v0,-1rtn: lw $ra,4($sp) addiu $sp,$sp,8 jr $ra

int sqr(int x) {   if (x > 1) x = sqr(x-1)+x+x-1;  return x; }30Slide31

Conclusions

Need a convention (contract) between caller and calleeImplement stack for storing each procedure’s variablesProcedure calls can now be arbitrarily nestedRecursion possible too

FOLLOW the convention meticulously!

31Slide32

A few procedure templatesSlide33

Ex1: simple leaf proc

(w/o stack frame)main:doesn’t need to preserve any temporary registersproc1:is a leaf

proc

(doesn’t call any other

proc)doesn’t touch any saved

regs

main:

jal

proc1 # call proc1

... # other main stuff

proc1:

... # do the task

jr $ra # return33

stack frame

none

needed!Slide34

Ex2: leaf proc with stack frame

main:doesn’t need to preserve any temporary registersproc1:is leaf; doesn’t touch any saved regs

creates minimal stack frame (but doesn’t really need it)

main:

jal

proc1 # call proc1

... # other main stuff

proc1:

addi

$

sp

, $

sp, -8 sw $ra, 4($sp) # Save $ra sw $fp, 0($sp

) # Save $

fp

addi $fp, $sp, 4 # Set $

fp

... # do the task

addi $sp, $fp, 4 # Restore $sp lw $ra, 0($fp) # Restore $

ra lw $fp, -4($fp) # Restore $fp jr $ra # Return$

ra$fp

$sp

$fpSlide35

Ex3: minimal non-leaf proc

proc1:calls proc2doesn’t need to preserve any data values in regscreates minimal stack frame (and needs it for saving return address)

proc1:

addi

$

sp

, $

sp

, -8

sw

$

ra, 4($sp) # Save $ra sw $fp, 0($sp) # Save $fp

addi

$fp, $sp, 4 # Set $fp

...

jal proc2 # call another ... addi $sp, $fp, 4 # Restore $sp lw

$ra, 0($fp) # Restore $ra lw $fp, -4($fp) # Restore $fp jr $

ra # Return$ra$fp

$sp

$fpSlide36

Ex4: leaf proc that saves

regsproc1:is leafneeds to save/restore $s2-$s3creates more of a stack frame

proc1:

addi

$

sp

, $

sp

, -8

sw

$

ra, 4($sp) # Save $ra sw $fp, 0($sp) # Save $fp

addi

$fp, $sp, 4 # Set $fp

addi $sp, $sp, -8 # room for $s2-$s3

sw $s2, 4($sp) # Save $s2 sw $s3, 0($sp) # Save $s3 ... # do the task lw $s2, -8($fp) # restore $s2 lw $s3, -12($fp) # restore $s3 addi $sp, $

fp, 4 # Restore $sp lw $ra, 0($fp) # Restore $ra lw $fp, -4($fp

) # Restore $fp jr $ra # Return$ra

$fp$s2$s3

$sp

$fpSlide37

Ex4: more general non-leaf proc

proc1:calls proc2needs to save/restore $s2-$s3creates more of a stack frame

proc1:

addi

$

sp

, $

sp

, -8

sw

$

ra, 4($sp) # Save $ra sw $fp, 0($sp) # Save $fp

addi

$fp, $sp, 4 # Set $fp

addi $sp, $sp, -8 # room for $s2-$s3

sw $s2, 4($sp) # Save $s2 sw $s3, 0($sp) # Save $s3 ... jal proc2 # call another ... lw $s2, -8($fp) # restore $s2 lw $s3, -12($fp) # restore $s3

addi $sp, $fp, 4 # Restore $sp lw $ra, 0($fp) # Restore $ra lw

$fp, -4($fp) # Restore $fp jr $ra # Return

$ra$fp$s2$s3

$sp

$fpSlide38

Ex5: proc that needs to protect temporaries

proc1:calls proc2needs to protect $t0-$t1 from proc2

proc1:

addi

$

sp

, $

sp

, -8

sw

$

ra, 4($sp) # Save $ra sw $fp, 0($sp) # Save $fp

addi

$fp, $sp, 4 # Set $fp

addi

$sp, $sp, -8 # room for $s2-$s3 sw $s2, 4($sp) # Save $s2 sw $s3, 0($

sp) # Save $s3 addi $sp, $sp, -8 # room for $t0-$t1 ... sw $t0, -16($fp) # Save $t0

sw $t1, -20($fp) # Save $t1 jal proc2 # call another lw $t0, -16($fp) # Restore

$t0 lw $t1, -20($fp) # Restore $t1 ... lw $s2, -8($fp) # restore $s2 lw $s3, -12($fp) # restore $s3 addi $sp, $fp, 4 # Restore $sp

lw $ra, 0($fp) # Restore $ra lw $fp, -4($fp) # Restore $fp jr $

ra # Return$ra$fp

$s2$s3

$t0

$t1

$

sp

$

fpSlide39

Ex5: proc that needs to protect temporaries

proc1:calls proc2has a local var i

proc1:

addi

$

sp

, $

sp

, -8

sw

$

ra, 4($sp) # Save $ra sw $fp, 0($sp) # Save $

fp

addi $fp, $sp, 4 # Set $

fp

addi $sp, $sp, -8 # room for $s2-$s3 sw $s2, 4($sp) # Save $s2 sw

$s3, 0($sp) # Save $s3 addi $sp, $sp, -4 # local var i sw $0, 0($sp

) # Set i=0, e.g. addi $sp, $sp, -8 # room for $t0-$t1 ...

sw $t0, -16($fp) # Save $t0 sw $t1, -20($fp) # Save $t1 jal proc2 # call another lw $t0, -16($fp) # Restore

$t0 lw $t1, -20($fp) # Restore $t1 ... lw $s2, -8($fp) # restore $s2 lw $s3, -12($fp) # restore $s3 addi $sp, $fp, 4 # Restore $sp

lw $ra, 0($fp) # Restore $ra lw $fp, -4($fp) # Restore $

fp jr $ra # Return$ra

$

fp

$s2

$s3

$t0

$t1

local

var

i

$

sp

$

fpSlide40

Ex6: call proc2 with more than 4 args

proc1:calls proc2… with more than 4 args

proc1:

addi

$

sp

, $

sp

, -8

sw

$

ra, 4($sp) # Save $ra sw $fp, 0($sp) # Save $

fp

addi $fp, $sp, 4 # Set $

fp

... addi $sp, $sp, -4 # space for arg[4] ... ori $a0, $0, 40 # Put 40 in ... sw

$a0, 0($sp) # ... arg[4] ori $a0, $0, 0 # Put 0 in $a0 ori $a1, $0, 10 # Put 10 in $a1 ori $a2, $0, 20 # Put 20 in $a2 ori $a3, $0, 30 # Put 30 in $a3 jal

proc2 addi $sp, $fp, 4 # Restore $sp lw

$ra, 0($fp) # Restore $ra lw $fp, -4($fp) # Restore $fp jr $ra # Return

$ra$fp$s2$s3

$t0$t1local var “

i”arg[4]

$

sp

$

fp

proc1’s stack frame