15-410 “Way easier than when we were students” Stack Discipline Jan. 14, 2004 Dave Eckhardt Bruce Maggs Review slides from 15-213 originally developed by Randy Bryant and Dave O’Halloran. -1- L02_Stack 15-410, S’04 Outline Topics Process memory model IA32 stack organization Register saving conventions Before & after main() Project 0 -2- 15-410, S’04 Private Address Spaces Each process has its own private address space. 0xffffffff kernel virtual memory (code, data, heap, stack) 0xc0000000 0x40000000 user stack (created at runtime) read/write segment (.data, .bss) -3- 0 %esp (stack pointer) memory mapped region for shared libraries run-time heap (managed by malloc) 0x08048000 memory invisible to user code read-only segment (.init, .text, .rodata) brk loaded from the executable file unused 15-410, S’04 FF Linux Memory Layout Stack Runtime stack (8MB limit) C0 BF Upper 2 hex digits of address Dynamically allocated storage When call malloc, calloc, new Shared/Dynamic Libraries aka Shared Objects 80 7F Red Hat v. 6.2 ~1920MB memory limit 40 3F -4- Stack Heap 08 00 Heap Library routines (e.g., printf, malloc) Linked into object code when first executed Windows has “DLLs” (semantic differences) Data, BSS Shared Libraries Heap Data Text Statically allocated data E.g., arrays & strings declared in code Text, RODATA Text - Executable machine instructions RODATA – Read-only (e.g., “const”) 15-410, S’04 Linux Memory Allocation Initially BF Stack 80 7F Some Heap Linked BF Stack 80 7F BF Stack 80 7F More Heap BF Stack 80 7F Heap Heap 40 3F 40 3F Libraries 40 3F Libraries 40 3F Libraries Heap 08 00 -5- Data Text 08 00 Data Text 08 00 Data Text 08 00 Data Text 15-410, S’04 IA32 Stack Region of memory managed with stack discipline Grows toward lower addresses Register %esp indicates lowest stack address Stack “Bottom” Increasing Addresses address of top element Stack Pointer %esp Stack Grows Down Stack “Top” -6- 15-410, S’04 IA32 Stack Pushing Stack “Bottom” Pushing pushl Src Fetch operand at Src Decrement %esp by 4 Increasing Addresses Write operand at address given by %esp Stack Pointer %esp Stack Grows Down -4 Stack “Top” -7- 15-410, S’04 IA32 Stack Popping Stack “Bottom” Popping popl Dest Read operand at address given by %esp Increment %esp by 4 Increasing Addresses Write to Dest Stack Pointer %esp Stack Grows Down +4 Stack “Top” -8- 15-410, S’04 Procedure Control Flow Use stack to support procedure call and return Procedure call: call label label Push return address on stack; Jump to Return address value Address of instruction beyond call Example from disassembly 804854e: e8 3d 06 00 00 <main> 8048553: 50 call 8048b90 pushl %eax Return address = 0x8048553 Procedure return: ret - 10 - Pop address from stack; Jump to address 15-410, S’04 Procedure Call Example 804854e: 8048553: e8 3d 06 00 00 50 call 0x110 0x110 0x10c 0x10c 0x108 123 0x108 call pushl 8048b90 <main> %eax 8048b90 123 0x104 0x8048553 %esp %esp 0x108 %eip 0x804854e 0x108 0x104 %eip 0x8048b90 0x804854e %eip is program counter - 11 - 15-410, S’04 Procedure Return Example 8048591: c3 ret ret 0x110 0x110 0x10c 0x10c 0x108 123 0x108 0x104 0x8048553 %esp 0x104 %eip 0x8048591 123 0x8048553 %esp 0x104 0x108 %eip 0x8048553 0x8048591 %eip is program counter - 12 - 15-410, S’04 Stack-Based Languages Languages that Support Recursion e.g., C, Pascal, Java Code must be “Reentrant” Multiple simultaneous instantiations of single procedure Need some place to store state of each instantiation Arguments Local variables Return pointer Stack Discipline State for given procedure needed for limited time From when called to when return Callee returns before caller does Stack Allocated in Frames state for single procedure instantiation - 13 - 15-410, S’04 Call Chain Example Code Structure yoo(…) { • • who(); • • } yoo who(…) { • • • amI(); • • • amI(); • • • } Procedure amI recursive - 14 - Call Chain who amI amI(…) { • • amI(); • • } amI amI amI 15-410, S’04 Stack Frames Contents Local variables Return information Temporary space yoo who amI Management Space allocated when enter procedure “Set-up” code Deallocated when return “Finish” code Pointers Stack pointer %esp indicates stack top Frame pointer %ebp indicates - 15 - start of current frame Frame Pointer %ebp proc Stack Pointer %esp Stack “Top” 15-410, S’04 IA32/Linux Stack Frame Current Stack Frame (“Top” to Bottom) Parameters for function about to call Caller Frame “Argument build” Local variables If can’t keep in registers Arguments Frame Pointer (%ebp) Saved register context Old frame pointer Return Addr Old %ebp Saved Registers + Local Variables Caller Stack Frame Return address Pushed by call instruction Arguments for this call - 16 - Stack Pointer (%esp) Argument Build 15-410, S’04 swap Calling swap from call_swap int zip1 = 15213; int zip2 = 91125; void call_swap() { swap(&zip1, &zip2); } void swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0; } - 17 - call_swap: • • • pushl $zip2 pushl $zip1 call swap • • • # Global Var # Global Var • • • Resulting Stack &zip2 &zip1 Rtn adr %esp 15-410, S’04 swap void swap(int *xp, int *yp) { int t0 = *xp; int t1 = *yp; *xp = t1; *yp = t0; } swap: pushl %ebp movl %esp,%ebp pushl %ebx movl movl movl movl movl movl 12(%ebp),%ecx 8(%ebp),%edx (%ecx),%eax (%edx),%ebx %eax,(%edx) %ebx,(%ecx) movl -4(%ebp),%ebx movl %ebp,%esp popl %ebp ret - 18 - Set Up Body Finish 15-410, S’04 swap Setup #1 Resulting Stack Entering Stack %ebp %ebp • • • • • • &zip2 yp &zip1 xp Rtn adr %esp Rtn adr Old %ebp %esp swap: pushl %ebp movl %esp,%ebp pushl %ebx - 19 - 15-410, S’04 swap Setup #2 Resulting Stack Entering Stack %ebp • • • • • • &zip2 yp &zip1 xp Rtn adr %esp Rtn adr Old %ebp %ebp %esp swap: pushl %ebp movl %esp,%ebp pushl %ebx - 20 - 15-410, S’04 swap Setup #3 Resulting Stack Entering Stack %ebp • • • • • • &zip2 yp &zip1 xp Rtn adr %esp Rtn adr Old %ebp %ebp Old %ebx %esp swap: pushl %ebp movl %esp,%ebp pushl %ebx - 21 - 15-410, S’04 Effect of swap Setup Entering Stack Resulting Stack %ebp • • • Offset (relative to %ebp) &zip2 12 yp &zip1 8 xp 4 Rtn adr Rtn adr %esp movl 12(%ebp),%ecx # get yp movl 8(%ebp),%edx # get xp . . . - 22 - • • • 0 Old %ebp %ebp Old %ebx %esp Body 15-410, S’04 swap Finish #1 swap’s Stack Offset • • • Offset 12 yp 12 yp 8 xp 8 xp 4 Rtn adr 4 Rtn adr 0 Old %ebp %ebp 0 Old %ebp %ebp -4 Old %ebx %esp -4 Old %ebx %esp Observation Saved & restored register %ebx - 23 - • • • movl -4(%ebp),%ebx movl %ebp,%esp popl %ebp ret 15-410, S’04 swap Finish #2 swap’s Stack Offset swap’s Stack • • • Offset • • • 12 yp 12 yp 8 xp 8 xp 4 Rtn adr 4 Rtn adr 0 Old %ebp %ebp -4 Old %ebx %esp 0 Old %ebp %ebp %esp movl -4(%ebp),%ebx movl %ebp,%esp popl %ebp ret - 24 - 15-410, S’04 swap Finish #3 swap’s Stack Offset %ebp swap’s Stack • • • Offset • • • 12 yp 12 yp 8 xp 8 xp 4 Rtn adr 4 Rtn adr 0 Old %ebp %ebp %esp %esp movl -4(%ebp),%ebx movl %ebp,%esp popl %ebp ret - 25 - 15-410, S’04 swap Finish #4 %ebp swap’s Stack %ebp • • • • • • 12 yp &zip2 8 xp &zip1 4 Rtn adr Offset Exiting Stack %esp %esp Observation Saved & restored register %ebx Didn’t do so for %eax, %ecx, or %edx - 26 - movl -4(%ebp),%ebx movl %ebp,%esp popl %ebp ret 15-410, S’04 Register Saving Conventions 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(%ebp), %edx addl $91125, %edx • • • ret Contents of register %edx overwritten by who - 27 - 15-410, S’04 Register Saving Conventions When procedure yoo calls who: yoo is the caller, who is the callee Can Register be Used for Temporary Storage? Conventions “Caller Save” Caller saves temporary in its frame before calling “Callee Save” Callee saves temporary in its frame before using - 28 - 15-410, S’04 IA32/Linux Register Usage Integer Registers %eax Two have special uses %ebp, %esp Three managed as callee-save %ebx, %esi, %edi Old values saved on stack prior to using Caller-Save Temporaries %ecx %ebx Callee-Save Temporaries - 29 - Register %eax also stores returned value %esi %edi Three managed as caller-save %eax, %edx, %ecx Do what you please, but expect any callee to do so, as well %edx %esp Special %ebp 15-410, S’04 Stack Summary The Stack Makes Recursion Work Private storage for each instance of procedure call Instantiations don’t clobber each other Addressing of locals + arguments can be relative to stack positions Can be managed by stack discipline Procedures return in inverse order of calls IA32 Procedures Combination of Instructions + Conventions Call / Ret instructions Register usage conventions Caller / Callee save %ebp and %esp Stack frame organization conventions - 30 - 15-410, S’04 Before & After main() int main(int argc, char *argv[]) { if (argc > 1) { printf(“%s\n”, argv[1]); } else { char *av[3] = { 0, 0, 0 }; av[0] = argv[0]; av[1] = “Fred”; execvp(av[0], av); } return (1); } - 31 - 15-410, S’04 The Mysterious Parts argc, argv Strings from one program Available while another program is running Which part of the memory map are they in? How did they get there? What happens when main() does “return(1)” ? There's no more program to run...right? Where does the 1 go? How does it get there? 410 students should seek to abolish mystery - 32 - 15-410, S’04 The Mysterious Parts argc, argv Strings from one program Available while another program is running Inter-process sharing/information transfer is OS's job OS copies strings from old address space to new in exec() Traditionally placed “below bottom of stack” arg vector main() printf() .... - 33 - 15-410, S’04 The Mysterious Parts What happens when main() does “return(1)”??? Defined to have same effect as “exit(1)” The “main() wrapper” Receives argc, argv from OS Calls main(), then calls exit() Provided by C library, traditionally in “crt0.s” Often has a “strange” name /* not actual code */ void ~~main(int argc, char *argv[]) { exit(main(argc, argv)); } - 34 - 15-410, S’04 Project 0 - “Stack Crawler” C/Assembly function Can be called by any C function Prints stack frames in a symbolic way ---Stack Function Function Function Function Function Trace Follows--fun3(c='c', d=2.090000d), in fun2(f=35.000000f), in fun1(count=0), in fun1(count=1), in fun1(count=2), in Key question - 35 - How do I know 0x80334720 is “fun1”? How do I know fun3()'s second parameter is “d”? 15-410, S’04 Project 0 “Data Flow” fun.c tb.c tb_globals.c symbol-table array many blank slots - 36 - 15-410, S’04 Project 0 “Data Flow” libtraceback.a fun.o tb.o tb_globals.o - 37 - 15-410, S’04 Project 0 “Data Flow” fun fun.o mutate symtabgen tb.o tb_globals.o debugger info simplify - 38 - 15-410, S’04 Summary Review of stack knowledge What makes main() special Project 0 overview Start interviewing Project 2/3/4 partners! - 39 - 15-410, S’04