ProceduresandtheCallStack
Topics• Procedures• Callstack• Procedure/stack instructions• Callingconventions• Register-saving conventions
WhyProcedures?Whyfunctions?Whymethods?
ProceduralAbstraction
int contains_char(char* haystack, char needle) {while (*haystack != '\0') {
if (*haystack == needle) return 1;haystack++;
}return 0;
}
Implementing Procedures
Howdoesacallerpassarguments toaprocedure?
Howdoesacallergetareturnvaluefromaprocedure?
Wheredoesaprocedurestorelocalvariables?
Howdoesaprocedureknowwheretoreturn(whatcodetoexecutenextwhendone)?
Howdoproceduressharelimitedregistersandmemory?
3
CallChainyoo(…){
••who();••
}
who(…){
• • •ru();• • •ru();• • •
}
ru(…){
•••
}
yoo
who
ru
ExampleCallChain
ru
4
FirstTry(broken)
yoo:
jmp whoback:
stop:
who:
done:jmp back
WhatifIwanttocallafunctionmultipletimes?
FirstTry(broken)
who:
jmp ruback2:
jmp ruback2:
stop:
ru:
done:jmp back2
12
65 3,7
89
4
WhatifIwanttocallafunctionmultipletimes?
Implementing Procedures
Howdoesacallerpassarguments toaprocedure?
Howdoesacallergetareturnvaluefromaprocedure?
Wheredoesaprocedurestorelocalvariables?
Howdoesaprocedureknowwheretoreturn(whatcodetoexecutenextwhendone)?
Howdoproceduressharelimitedregistersandmemory?
7
Alltheseneedseparatestorage percall!(notjustperprocedure)
Addr Perm Contents Managedby Initialized
2N-1 Stack RW Procedurecontext Compiler Run-time
Heap RW Dynamicdata structures
Programmer,malloc/free,new/GC
Run-time
Statics RW Globalvariables/staticdatastructures
Compiler/Assembler/Linker Startup
Literals R Stringliterals Compiler/Assembler/Linker Startup
Text X Instructions Compiler/Assembler/Linker Startup
0
MemoryLayout
CallStack
Weseex86organization.Detailsdiffer acrossarchitectures, butbigideasareshared.
RegionofmemoryManagedwithstackdiscipline
%esp holdslowest stackaddress(address of"top"element)
StackPointer:%esp
stackgrowstoward
lower addresses
higheraddresses
Stack“Top”
Stack“Bottom”
9
(not extra-sensoryperception)
IA32CallStack: Push
pushl Src
Stack“Top”
Stack“Bottom”
StackPointer:%esp
10
stackgrowstoward
lower addresses
higheraddresses
IA32CallStack:Push
pushl Src1. Fetchvalue fromSrc2. Decrement%esp by4 (why4?)3. Storevalueatnewaddress
givenby%esp
Stack“Top”
Stack“Bottom”
-4
11
stackgrowstoward
lower addresses
higheraddresses
StackPointer:%esp
IA32CallStack:Pop
Stack“Top”
Stack“Bottom”
popl Dest
12
stackgrowstoward
lower addresses
higheraddresses
StackPointer:%esp
IA32CallStack: Pop
Stack“Top”
Stack“Bottom”
popl Dest
1. Loadvaluefromaddress%esp2. Writevalue toDest3. Increment%esp by4
13
Thosebitsarestill there;we’rejustnotusingthem.
stackgrowstoward
lower addresses
higheraddresses
StackPointer:%esp
CallChainExampleyoo(…){
••who();••
}
who(…){
• • •amI();• • •amI();• • •
}
amI(…){
••amI();••
}
yoo
who
amI
amI
amI
ExampleCallChain
amI
ProcedureamI isrecursive(calls itself)
14
Base/FramePointer:%ebp
Stackframessupportprocedurecalls.Contents
LocalvariablesFunctionargumentsReturn informationTemporaryspace
ManagementSpaceallocatedwhen procedure isentered
“Set-up”codeSpacedeallocated uponreturn
“Finish”code
Whynotjustgiveeveryprocedure apermanentchunkofmemorytoholditslocalvariables, etc?
%espStackPointer
CallerFrame
Stack“Top”
15
Frameforcurrent
procedure
Example
yoo(…){
••who();••
}
yoo
who
amI
amI
amI
amI
yoo
%ebp
%esp
Stack
26Howdidwerememberwheretopoint%ebp whenreturning?
ProcedureControlFlowInstructions
Procedurecall:call label1. Pushreturnaddress onstack2. Jumptolabel
Returnaddress: Address ofinstructionaftercall.Example:804854e: e8 3d 06 00 00 call 8048b90 <main>
8048553: 50 pushl %eax
Procedurereturn:ret1. Popreturn address fromstack2. Jumptoaddress
27
%esp
%eip 0x804854e
ProcedureCall/Return:1
0x108
0x10c
0x110
123
0x108
804854e: e8 3d 06 00 00 call 8048b90 <main>8048553: 50 pushl %eax
28
call 8048b90
%eip = instructionpointer=programcounter
%esp
%eip
%esp
%eip 0x804854e
0x108
0x108
0x10c
0x110
0x104
0x804854e
123
ProcedureCall/Return:2
0x108
0x10c
0x110
123
0x108
call 8048b90
804854e: e8 3d 06 00 00 call 8048b90 <main>8048553: 50 pushl %eax
0x8048553
0x104
%eip = instructionpointer=programcounter29
0x8048553
%esp
%eip
%esp
%eip 0x8048553
0x108
0x108
0x10c
0x110
0x104
0x804854e
0x8048553
123
ProcedureCall/Return:3
0x108
0x10c
0x110
123
0x108
call 8048b90
804854e: e8 3d 06 00 00 call 8048b90 <main>8048553: 50 pushl %eax
0x8048b90
0x104
%eip: programcounter30
+ 0x000063d
PC-relativeaddress
%esp
%eip
0x104
%esp
%eip 0x80485910x8048591
0x1040x104
0x108
0x10c
0x110
0x8048553
123
ProcedureCall/Return:4
0x108
0x10c
0x110
123
8048591: c3 ret
0x8048553
%eip: programcounter31
ret
0x8048553
0x108
IA32/LinuxStackFrame
33
ReturnAddress
SavedRegisters+
Local Variables
Argumentsfornextcall
…
Caller'sbasepointer
Argumentstocallee
CallerFrame
Base/Frame pointer%ebpStackpointer%esp
StackRegisters
CalleeFrame
Revisitingswap
int zip1 = 02481;int zip2 = 98195;
void call_swap() {swap(&zip1, &zip2);
}
void swap(int *xp, int *yp) {int t0 = *xp;int t1 = *yp;*xp = t1;*yp = t0;
}
call_swap:• • •pushl $zip2 # Global Varpushl $zip1 # Global Varcall swap• • •
&zip2
&zip1
Rtn adr %esp
ResultingStack•
••
Callingswap fromcall_swap
34
Revisitingswap
void swap(int *xp, int *yp) {int t0 = *xp;int t1 = *yp;*xp = t1;*yp = t0;
}
swap:pushl %ebpmovl %esp,%ebppushl %ebx
movl 12(%ebp),%ecxmovl 8(%ebp),%edxmovl (%ecx),%eaxmovl (%edx),%ebxmovl %eax,(%edx)movl %ebx,(%ecx)
movl -4(%ebp),%ebxmovl %ebp,%esppopl %ebpret
Body
SetUp
Finish
35
swap Setup#1
swap:pushl %ebpmovl %esp,%ebppushl %ebx
ResultingStack
&zip2
&zip1
Rtn adr
EnteringStack
•••
36
SetUp
call_sw
apfram
e
yp
xp
Rtn adr
Old%ebp
•••
%esp%ebp
%esp%ebp
swap Setup#2
swap:pushl %ebpmovl %esp,%ebppushl %ebx
&zip2
&zip1
Rtn adr
EnteringStack
•••
yp
xp
Rtn adr
Old%ebp
•••
ResultingStack
37
SetUp
call_sw
apfram
e
%esp%ebp
%esp%ebp
swap Setup#3
swap:pushl %ebpmovl %esp,%ebppushl %ebx
&zip2
&zip1
Rtn adr
EnteringStack
•••
yp
xp
Rtn adr
Old%ebp
•••
ResultingStack
38
Old%ebx
SetUp
call_sw
apfram
e
%esp%ebp
%esp%ebp
12
8
4
swap Body
&zip2
&zip1
Rtn adr
%esp
EnteringStack
•••
%ebp
yp
xp
Rtn adr
Old%ebp
•••
ResultingStack
Old%ebx
movl 12(%ebp),%ecx # get ypmovl 8(%ebp),%edx # get xp. . .
Offsetrelativetonew%ebp
39
Body
call_sw
apfram
e
%esp%ebp
swap Finish#1
yp
xp
Rtn adr
Old%ebp
•••
Old%ebx
movl -4(%ebp),%ebxmovl %ebp,%esppopl %ebpret
yp
xp
Rtn adr
Old%ebp
•••
ResultingStack
Old%ebx
40
Finish
FinishingStack
call_sw
apfram
e
%esp%ebp
%esp%ebp
swap Finish#2
yp
xp
Rtn adr
Old%ebp
•••
Old%ebx
movl -4(%ebp),%ebxmovl %ebp,%esppopl %ebpret
yp
xp
Rtn adr
Old%ebp
•••
ResultingStack
41
Finish
FinishingStack
call_sw
apfram
e
%esp%ebp
%esp%ebp
swap Finish#3
yp
xp
Rtn adr
Old%ebp
•••
Old%ebx
movl -4(%ebp),%ebxmovl %ebp,%esppopl %ebpret
ResultingStack
yp
xp
Rtn adr
•••
42
Finish
FinishingStack
call_sw
apfram
e
%esp%ebp
%esp%ebp
swap Finish#4
yp
xp
Rtn adr
Old%ebp
•••
Old%ebx
movl -4(%ebp),%ebxmovl %ebp,%esppopl %ebpret
yp
xp
•••
ResultingStack
43
Finish
FinishingStack
call_sw
apfram
e
%esp%ebp
%esp%ebp
Disassembledswap080483a4 <swap>:80483a4: 55 push %ebp80483a5: 89 e5 mov %esp,%ebp80483a7: 53 push %ebx80483a8: 8b 55 08 mov 0x8(%ebp),%edx80483ab: 8b 4d 0c mov 0xc(%ebp),%ecx80483ae: 8b 1a mov (%edx),%ebx80483b0: 8b 01 mov (%ecx),%eax80483b2: 89 02 mov %eax,(%edx)80483b4: 89 19 mov %ebx,(%ecx)80483b6: 5b pop %ebx80483b7: c9 leave 80483b8: c3 ret
8048409: e8 96 ff ff ff call 80483a4 <swap>804840e: 8b 45 f8 mov 0xfffffff8(%ebp),%eax
CallingCode
44
mov %ebp,%esppop %ebp
relativeaddress(little endian)
swap Finish#4
yp
xp
Rtn adr
Old%ebp
•••
Old%ebx
movl -4(%ebp),%ebxmovl %ebp,%esppopl %ebpret
yp
xp
•••
ResultingStack
45
Finish
FinishingStack
call_sw
apfram
e
ObservationSaved&restored register%ebxbutnot%eax,%ecx,or%edx
%esp%ebp
%esp%ebp
RegisterSavingConventionsWhenprocedureyoo callswho:
yoo isthecallerwho isthecallee
Willregistercontentsstillbethereafteraprocedurecall?yoo:
• • •movl $12345, %edxcall whoaddl %edx, %eax• • •ret
who:• • •movl 8(%ebp), %edxaddl $98195, %edx• • •ret
47
?
RegisterSavingConventionsWhenprocedureyoo callswho:
yoo isthecallerwho isthecallee
Willregistercontentsstillbethereafteraprocedurecall?Conventions
CallerSaveCaller saves temporaryvalues initsframebeforecalling
Callee SaveCallee saves temporaryvalues initsframe beforeusing
48
IA32/LinuxRegisterSavingConventions%eax, %edx, %ecx
Caller saves priortocallif needsvaluesaftercall
%eaxalsousedtoreturnintegervalue
%ebx, %esi, %ediCallee saves ifwilluse
%esp, %ebpspecialformofcallee saverestored tooriginalvaluesbefore returning
%eax
%edx
%ecx
%ebx
%esi
%edi
%esp
%ebp
Caller-SaveTemporaries
Callee-SaveTemporaries
Special
49
APuzzle
*p = d;return x - c;
movsbl 12(%ebp),%edxmovl 16(%ebp),%eaxmovl %edx,(%eax)movswl 8(%ebp),%eaxmovl 20(%ebp),%edxsubl %eax,%edxmovl %edx,%eax
WritetheCfunctionheader,types,andorderofparameters.
Cfunctionbody:
assembly:
movsbl =movesign-extendingabytetoalong(4-byte)movswl =movesign-extendingaword(2-byte)toalong(4-byte)
Example:PointerstoLocalVariables
51
void s_helper(int x, int *accum) {if (x <= 1) {
return;} else {
int z = *accum * x;*accum = z;s_helper (x-1,accum);
}}
int sfact(int x) {int val = 1;s_helper(x, &val);return val;
}
Top-LevelCall RecursiveProcedure
Passpointertoupdatelocation
sfact(3) val =1s_helper(3,&val) val =3s_helper(2,&val) val =6s_helper(1,&val) val =6.
Temp.Space
%esp
Creating&Initializing Pointer
52
int sfact(int x) {int val = 1;s_helper(x, &val);return val;
}
_sfact:pushl %ebp # Save %ebpmovl %esp,%ebp # Set %ebpsubl $16,%esp # Add 16 bytes movl 8(%ebp),%edx # edx = xmovl $1,-4(%ebp) # val = 1
Initialpartofsfact
x
Rtn adr
Old%ebp0
4
8
-4 val = 1
Unused-12
-8
-16
_sfact:pushl %ebp # Save %ebpmovl %esp,%ebp # Set %ebpsubl $16,%esp # Add 16 bytes movl 8(%ebp),%edx # edx = xmovl $1,-4(%ebp) # val = 1
_sfact:pushl %ebp # Save %ebpmovl %esp,%ebp # Set %ebpsubl $16,%esp # Add 16 bytes movl 8(%ebp),%edx # edx = xmovl $1,-4(%ebp) # val = 1
_sfact:pushl %ebp # Save %ebpmovl %esp,%ebp # Set %ebpsubl $16,%esp # Add 16 bytes movl 8(%ebp),%edx # edx = xmovl $1,-4(%ebp) # val = 1
%esp
%esp%ebp
Muststoreval inmemory(stack);registersdonothaveaddresses.
PassingPointer
53
int sfact(int x) {int val = 1;s_helper(x, &val);return val;
}
leal -4(%ebp),%eax # Compute &valpushl %eax # Push on stackpushl %edx # Push xcall s_helper # callmovl -4(%ebp),%eax # Return val• • • # Finish
Callings_helper fromsfact
x
Rtn adr
Old%ebp %ebp0
4
8
val = 1-4
Unused-12
-8
-16 %esp
x
&val
Stackattime ofcall:
leal -4(%ebp),%eax # Compute &valpushl %eax # Push on stackpushl %edx # Push xcall s_helper # callmovl -4(%ebp),%eax # Return val• • • # Finish
leal -4(%ebp),%eax # Compute &valpushl %eax # Push on stackpushl %edx # Push xcall s_helper # callmovl -4(%ebp),%eax # Return val• • • # Finish
val=x!
Muststoreval inmemory(stack);registersdonothaveaddresses.
IA32/Linux ProcedureSummarycall, ret, push, pop
Stackdisciplinefitsprocedurecall/return.*IfPcallsQ,Qreturns beforeP,includingrecursion.
Conventionssupportarbitraryfunctioncalls.Safelystoreper-call values inlocalstackframeandcallee-saved registersPushfunctionarguments attopofstackbefore callResult returned in%eax
*Take251tolearnabout languageswhereitdoesn't.
ReturnAddr
SavedRegisters
+Local
Variables
ArgumentBuild
Old%ebp
Arguments
CallerFrame
%ebp
%esp
54