Machine- Level Programming III: Switch Statements and IA32 Procedures CS 485: Systems Programming Fall 2015 Instructor: James Griffioen Adapted from slides by R. Bryant and D. O Hallaron (hjp://csapp.cs.cmu.edu/public/instructors.html)
Today IA 32 Procedures Stack Structure Calling ConvenQons IllustraQons of Recursion & Pointers 20
Stack- Based Languages Languages that support recursion e.g., C, Pascal, Java Code must be Reentrant MulQple simultaneous instanqaqons of single procedure Need some place to store state of each instanqaqon Arguments Local variables Return pointer Stack discipline State for given procedure needed for limited Qme From when called to when return Callee returns before caller does Stack allocated in Frames state for single procedure instanqaqon 21
Call Chain Example yoo( ) { who(); who( ) { (); (); ( ) { (); Example Call Chain yoo who Procedure () is recursive 22
Stack Frames Contents Local variables Return informaqon Temporary space Frame Pointer: Stack Pointer: Previous Frame Frame for proc Management Space allocated when enter procedure Set- up code Deallocated when return Finish code Stack Top 23
Example Stack yoo( ) { who(); yoo who yoo 24
Example Stack yoo( ) { who( ) { who(); (); (); yoo who yoo who 25
Example Stack yoo( ) { who( ) { ( ) who(); (); { (); (); yoo who yoo who 26
Example Stack yoo( ) { who( ) { ( ) who(); (); { ( ) (); { (); (); yoo who yoo who 27
Example Stack yoo( ) { who( ) { ( ) who(); (); { ( ) (); { (); ( ) { (); (); yoo who yoo who 28
Example Stack yoo( ) { who( ) { ( ) who(); (); { ( ) (); { (); (); yoo who yoo who 29
Example Stack yoo( ) { who( ) { ( ) who(); (); { (); (); yoo who yoo who 30
Example Stack yoo( ) { who( ) { who(); (); (); yoo who yoo who 31
Example Stack yoo( ) { who( ) { ( ) who(); (); { (); (); yoo who yoo who 32
Example Stack yoo( ) { who( ) { who(); (); (); yoo who yoo who 33
Example Stack yoo( ) { who(); yoo who yoo 34
IA32 Stack Region of memory managed with stack discipline Grows toward lower addresses Stack BoJom Increasing Addresses Register contains lowest stack address address of top element Stack Pointer: Stack Grows Down Stack Top 35
IA32 Stack: Push pushl Src Fetch operand at Src Decrement by 4 Write operand at address given by Stack BoJom Increasing Addresses Stack Pointer: - 4 Stack Grows Down Stack Top 36
IA32 Stack: Pop Stack BoJom Increasing Addresses Stack Pointer: +4 Stack Grows Down Stack Top 37
Procedure Control Flow Use stack to support procedure call and return Procedure call: call label Push return address on stack Jump to label Return address: Address of the next instrucqon right aaer call Example from disassembly 804854e: e8 3d 06 00 00 call 8048b90 <main> 8048553: 50 pushl %eax Return address = 0x8048553 Procedure return: ret Pop address from stack Jump to address 38
Procedure Call Example 804854e: e8 3d 06 00 00 call 8048b90 <main> 8048553: 50 pushl %eax Before Call call 8048b90 0x110 0x110 After Call 0x10c 0x10c 0x108 123 0x108 123 0x104 0x8048553 0x108 0x104 %eip 0x804854e %eip 0x8048b90 %eip: program counter 39
Procedure Return Example 8048591: c3 ret After ret ret Before ret 0x110 0x10c 0x110 0x10c 0x108 123 0x108 123 0x104 0x8048553 0x8048553 0x104 0x108 %eip 0x8048591 %eip 0x8048553 %eip: program counter 40
IA32/Linux Stack Frame Current Stack Frame ( Top to BoNom) Argument build: Parameters for funcqon about to call Local variables If can t keep in registers Saved register context Old frame pointer Frame pointer Caller Frame Arguments Return Addr Old Caller Stack Frame Return address Pushed by call instrucqon Arguments for this call Stack pointer Saved Registers + Local Variables Argument Build 41
RevisiPng swap int course1 = 15213; int course2 = 18243; void call_swap() { swap(&course1, &course2); Calling swap from call_swap call_swap: subl $8, movl $course2, 4() movl $course1, () call swap void swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0; &course 2 &course 1 Rtn adr ResulQng Stack subl call 42
RevisiPng swap void swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0; swap: pushl movl, pushl %ebx movl 8(), %edx movl 12(), %ecx movl (%edx), %ebx movl (%ecx), %eax movl %eax, (%edx) movl %ebx, (%ecx) popl %ebx popl ret Set Up Body Finish 43
swap Setup #1 Entering Stack ResulQng Stack &course2 yp &course1 xp Rtn adr Rtn adr Old swap: pushl movl, pushl %ebx 44
swap Setup #2 Entering Stack ResulQng Stack &course2 yp &course1 xp Rtn adr Rtn adr Old swap: pushl movl, pushl %ebx 45
swap Setup #3 Entering Stack ResulQng Stack &course2 &course1 Rtn adr yp xp Rtn adr swap: pushl movl, pushl %ebx Old Old %ebx 46
swap Body Entering Stack ResulQng Stack Offset relaqve to &course2 &course1 Rtn adr 12 8 4 yp xp Rtn adr Old Old %ebx movl 8(),%edx # get xp movl 12(),%ecx # get yp... 47
swap Finish Stack Before Finish popl %ebx popl ResulQng Stack yp xp Rtn adr Old Old %ebx yp xp Rtn adr ObservaQon Saved and restored register %ebx Not so for %eax, %ecx, %edx 48
Disassembled swap 08048384 <swap>: 8048384: 55 push 8048385: 89 e5 mov, 8048387: 53 push %ebx 8048388: 8b 55 08 mov 0x8(),%edx 804838b: 8b 4d 0c mov 0xc(),%ecx 804838e: 8b 1a mov (%edx),%ebx 8048390: 8b 01 mov (%ecx),%eax 8048392: 89 02 mov %eax,(%edx) 8048394: 89 19 mov %ebx,(%ecx) 8048396: 5b pop %ebx 8048397: 5d pop 8048398: c3 ret Calling Code 80483b4: movl $0x8049658,0x4() # Copy &course2 80483bc: movl $0x8049654,() # Copy &course1 80483c3: call 8048384 <swap> # Call swap 80483c8: leave # Prepare to return 80483c9: ret # Return 49
Today IA 32 Procedures Stack Structure Calling ConvenQons IllustraQons of Recursion & Pointers 50
Register Saving ConvenPons When procedure yoo calls who: yoo is the caller who is the callee Can register be used for temporary storage? yoo: movl $15213, %edx call who addl %edx, %eax ret who: movl 8(), %edx addl $18243, %edx ret Contents of register %edx overwrijen by who This could be trouble something should be done! Need some coordinaqon 51
Register Saving ConvenPons When procedure yoo calls who: yoo is the caller who is the callee Can register be used for temporary storage? ConvenPons Caller Save Caller saves temporary values in its frame before the call Callee Save Callee saves temporary values in its frame before using 52
IA32/Linux+Windows Register Usage %eax, %edx, %ecx Caller saves prior to call if values are used later %eax also used to return integer value %ebx, %esi, %edi Callee saves if wants to use them, special form of callee save Restored to original values upon exit from procedure Caller- Save Temporaries Callee- Save Temporaries Special %eax %edx %ecx %ebx %esi %edi 53
X86-64 Registers differences from IA32 Register Names: Register names start with r instead of e. For example the %eax register becomes %rax New Registers: There are 8 addiqonal registers idenqfied as %r8, %r9, %r10,, %r15. Working with 8, 16, and 32 bits: To only use part of a register you can add a suffix to a register name. For example %r8d refers to the the low order 32 bits. Other suffixes are b (8 bits), w (16 bits), and d (32 bits). Passing Parameters: The first (up to) 6 arguments to a procedure are passed in registers, not on the stack. In parqcular, they are passed in reverse order (i.e., lea to right in the funcqon call) in registers %rdi, %rsi, %rdx, %rcx, %r8, and %r9. If there are more than 6 parameters, they are passed on the stack in call order (from right to lea). Calling ConvenQons: Registers %rbp, %rbx, %r12, %r13, %r14, and %r15 are callee- saves registers. All other registers are caller- saves. 54
Today IA 32 Procedures Stack Structure Calling ConvenQons IllustraQons of Recursion & Pointers 55
Recursive FuncPon /* Recursive popcount */ int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1); Registers %eax, %edx used without first saving %ebx used, but saved at beginning & restored at end pcount_r: pushl movl, pushl %ebx subl $4, movl 8(), %ebx movl $0, %eax testl %ebx, %ebx je.l3 movl %ebx, %eax shrl %eax movl %eax, () call pcount_r movl %ebx, %edx andl $1, %edx leal (%edx,%eax), %eax.l3: addl $4, popl %ebx popl ret 56
Recursive Call #1 /* Recursive popcount */ int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1); AcPons Save old value of %ebx on stack Allocate space for argument to recursive call Store x in %ebx %ebx x pcount_r: pushl movl, pushl %ebx subl $4, movl 8(), %ebx x Rtn adr Old Old %ebx 57
Recursive Call #2 /* Recursive popcount */ int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1); movl $0, %eax testl %ebx, %ebx je.l3.l3: ret AcPons If x == 0, return with %eax set to 0 %ebx x 58
Recursive Call #3 /* Recursive popcount */ int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1); movl %ebx, %eax shrl %eax movl %eax, () call pcount_r AcPons Store x >> 1 on stack Make recursive call Effect %eax set to funcqon result %ebx sqll has value of x %ebx x Rtn adr Old Old %ebx x >> 1 59
Recursive Call #4 /* Recursive popcount */ int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1); movl %ebx, %edx andl $1, %edx leal (%edx,%eax), %eax Assume %eax holds value from recursive call %ebx holds x AcPons Compute (x & 1) + computed value Effect %eax set to funcqon result %ebx x 60
Recursive Call #5 /* Recursive popcount */ int pcount_r(unsigned x) { if (x == 0) return 0; else return (x & 1) + pcount_r(x >> 1); L3: addl$4, popl%ebx popl ret AcPons Restore values of %ebx and Restore Rtn adr Old Old %ebx %ebx Old %ebx 61
ObservaPons About Recursion Handled Without Special ConsideraPon Stack frames mean that each funcqon call has private storage Saved registers & local variables Saved return pointer Register saving convenqons prevent one funcqon call from corrupqng another s data Stack discipline follows call / return pajern If P calls Q, then Q returns before P Last- In, First- Out Also works for mutual recursion P calls Q; Q calls P 62
Pointer Code GeneraQng Pointer /* Compute x + 3 */ int add3(int x) { int localx = x; incrk(&localx, 3); return localx; Referencing Pointer /* Increment value by k */ void incrk(int *ip, int k) { *ip += k; add3 creates pointer and passes it to incrk 63
CreaPng and IniPalizing Local Variable int add3(int x) { int localx = x; incrk(&localx, 3); return localx; Variable localx must be stored on stack Because: Need to create pointer to it Compute pointer as - 4() 8 4 x Rtn adr First part of add3 add3: pushl movl, subl $24, # Alloc. 24 bytes movl 8(), %eax movl %eax, -4() # Set localx to x 0 Old -4 localx = x -8-12 Unused -16-20 -24 64
CreaPng Pointer as Argument int add3(int x) { int localx = x; incrk(&localx, 3); return localx; Use leal instrucpon to compute address of localx Middle part of add3 movl $3, 4() # 2 nd arg = 3 leal -4(), %eax # &localx movl %eax, () # 1 st arg = &localx call incrk 8 x 4 Rtn adr 0 Old -4 localx -8-12 Unused -16-20 3 +4-24 65
Retrieving local variable int add3(int x) { int localx = x; incrk(&localx, 3); return localx; Retrieve localx from stack as return value Final part of add3 movl -4(), %eax # Return val= localx leave ret 8 x 4 Rtn adr 0 Old -4 localx -8-12 Unused -16-20 -24 66
IA 32 Procedure Summary Important Points Stack is the right data structure for procedure call / return If P calls Q, then Q returns before P Recursion (& mutual recursion) handled by normal calling convenpons Can safely store values in local stack frame and in callee- saved registers Put funcqon arguments at top of stack Result return in %eax Pointers are addresses of values On stack or global Caller Frame Arguments Return Addr Old Saved Registers + Local Variables Argument Build 67