λ CS 251 Fall 2019 CS 240 Spring 2020 Principles of Programming Languages Foundations of Computer Systems Ben Wood Ben Wood Procedures and the Call Stack The call stack discipline x86 procedure call and return instructions x86 calling conventions x86 register-saving conventions https://cs.wellesley.edu/~cs240/s20/ x86 Procedures 1
Why procedures? Why functions? Why methods? int contains_char(char* haystack, char needle) { while (*haystack != '\0') { if (*haystack == needle) return 1; haystack++; } return 0; } Procedural Abstraction x86 Procedures 2
Implementing procedures ✓ 1. How does a caller pass arguments to a procedure? ✓ 2. How does a caller receive a return value from a procedure? ✓ ? 3. Where does a procedure store local variables? ?? 4. How does a procedure know where to return (what code to execute next when done)? ?? 5. How do procedures share limited registers and memory? x86 Procedures 3
Call Chain Procedure call/return: Jump? yoo who yoo (…) { • • • who (); • • • } yoo: who (…) { • • • 1 2 who: jmp who • • • back: 3 5 • • • 4 } ru(…) { jmp back • • • } But what if we want to call a function from multiple places in the code? x86 Procedures 4
Call Chain Procedure call/return: Jump? Broken! yoo who yoo(…) { • • • who(); ru ru • • • } who: who (…) { • • • 1 2 ru: ru (); jmp ru • • • back2: 6 ru (); 3,7 5 • • • jmp ru 4 } back2: ru (…) { jmp back2 9 8 • • • } But what if we want to call a function from multiple places in the code? Broken: needs to track context. x86 Procedures 5
Implementing procedures requires separate storage per call! (not just per procedure) ✓ 1. How does a caller pass arguments to a procedure? ✓ 2. How does a caller receive a return value from a procedure? ✓ ? 3. Where does a procedure store local variables? ?? 4. How does a procedure know where to return (what code to execute next when done)? ?? 5. How do procedures share limited registers and memory? x86 Procedures 6
reminder Memory Layout Addr Perm Contents Managed by Initialized 2 N -1 Stack RW Procedure context Compiler Run-time Programmer, Dynamic Heap malloc/free, RW Run-time data structures new/GC Global variables/ Compiler/ Statics RW Startup static data structures Assembler/Linker Compiler/ Literals R String literals Startup Assembler/Linker Compiler/ Text X Instructions Startup Assembler/Linker 0 x86 Procedures 7
Call stack tracks context Example Call Chain yoo(…) yoo { • who • who(); amI • amI who(…) • { } • amI amI(); • amI(…) amI amI(); { • • } if(…){ amI() } • Procedure amI is recursive } (calls itself) x86 Procedures 8
Call stack tracks context Stack yoo(…) yoo { yoo yoo • who %rsp • who(); amI • amI • } amI amI x86 Procedures 9
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { • who • • • • amI(); who(); who • • • amI • amI %rsp amI(); • • • • } amI } amI x86 Procedures 10
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { amI(…) • who • • • { • amI(); • who(); who • • • if(…){ amI • amI amI(); amI() • • • • } } amI amI } • %rsp } amI x86 Procedures 11
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { amI(…) • who • • • { amI(…) • amI(); { • who(); who • • • if(…){ • amI • amI amI(); amI() if(…){ • • • • } amI() } amI amI } • } } • } amI amI %rsp x86 Procedures 12
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { amI(…) • who • • • { amI(…) • amI(); { • amI(…) who(); who • • • if(…){ { • amI • amI amI(); amI() if(…){ • • • • • } amI() if(…){ } amI amI } • } amI() } • } } • amI amI } amI %rsp x86 Procedures 13
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { amI(…) • who • • • { amI(…) • amI(); { • amI(…) who(); who • • • if(…){ { • amI • amI amI(); amI() if(…){ • • • • • } amI() if(…){ } amI amI } • } amI() } • } } • amI amI } amI %rsp x86 Procedures 14
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { amI(…) • who • • • { amI(…) • amI(); { • who(); who • • • if(…){ • amI • amI amI(); amI() if(…){ • • • • } amI() } amI amI } • } } • } amI amI %rsp amI x86 Procedures 15
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo amI(…) { • who { • • • • • amI(); who(); who • • • if(…){ amI • amI amI() amI(); • } • • • } amI amI • } %rsp } amI amI amI x86 Procedures 16
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { • who • • amI(); who(); who • amI • amI %rsp amI(); • • } amI } amI amI amI amI x86 Procedures 17
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo amI(…) { • who { • • • amI(); who(); who • if(){ amI • amI amI() amI(); • } • } amI amI • } %rsp } amI x86 Procedures 18
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo amI(…) { • who { • • • amI(); who(); who • if(){ amI • amI amI() amI(); • } • } amI amI • } %rsp } amI x86 Procedures 19
Call stack tracks context Stack yoo(…) yoo who(…) { yoo yoo { • who • • amI(); who(); who • amI • amI %rsp amI(); • • } amI } amI amI x86 Procedures 20
Call stack tracks context Stack yoo(…) yoo { yoo yoo • who %rsp • who(); who amI • amI • } amI amI amI x86 Procedures 21
The call stack supports procedures. . . . Stack frame: section of stack Saved Registers used by one procedure call to Call er store context while running. Local Variables Frame higher Extra Arguments addresses to callee Procedure code manages stack frames explicitly. Return Address Setup: allocate space • where to continue on return at start of procedure. Cleanup: deallocate space • stack grows Call ee before return. Saved Registers toward Frame lower addresses Local Variables . . . Stack pointer %rsp x86 Procedures 22
Procedure control flow instructions Procedure call: callq target 1. Push return address on stack 2. Jump to target Return address: Address of instruction after call . 400544: callq 400550 <mult2> 400549: movq %rax,(%rbx) Procedure return: retq 1. Pop return address from stack 2. Jump to return address x86 Procedures 23
Call example Before callq Memory • 0x7fdf30 0000000000400540 <multstore>: • 0x7fdf28 • • • 0x7fdf20 400544: callq 400550 <mult2> 0x7fdf18 ??? 400549: mov %rax,(%rbx) %rsp %rip • • 0000000000400550 <mult2>: 0x400544 0x7fdf20 400550: mov %rdi,%rax • After callq • Memory 400557: retq • 0x7fdf30 • 0x7fdf28 callq target • 0x7fdf20 1. Push return address on stack 0x7fdf18 0x400549 2. Jump to target %rip %rsp 0x7fdf18 0x400550 x86 Procedures 24
Return example Before retq Memory • 0x7fdf30 0000000000400540 <multstore>: • 0x7fdf28 • • • 0x7fdf20 400544: callq 400550 <mult2> 0x7fdf18 0x400549 400549: mov %rax,(%rbx) %rsp %rip • • 0000000000400550 <mult2>: 0x400557 0x7fdf18 400550: mov %rdi,%rax • After retq • Memory 400557: retq • 0x7fdf30 • 0x7fdf28 retq • 0x7fdf20 1. Pop return address from stack 0x7fdf18 0x400549 2. Jump to return address %rip %rsp 0x7fdf20 0x400549 x86 Procedures 26
Procedure data flow conventions First 6 arguments: Remaining arguments: passed in registers passed on stack (in memory) Arg 1 High %rdi Diane’s • • • Addresses Silk Arg 2 %rsi Dress Arg n Arg 3 %rdx Costs $8 9 Arg 4 %rcx • • • Arg 5 %r8 Arg 8 Arg 6 %r9 Arg 7 Low Return Address Addresses Return value: Allocate stack space for arguments only when needed. passed in %rax %rax x86 Procedures 27
optional callq puzzle callq next next: popq %rax What gets stored into %rax? Why is there no ret instruction corresponding to the call ? What does this code do? (Hint: unusual use of call .) x86 Procedures 28
ex Procedure data flow puzzle C function body: huh( , , , ) { *p = d; return x - c; } Translated to x86 assembly: Reverse engineer the x86 huh procedure huh: and the body of the C huh function to fill movsbl %dl, %edx blanks in the C huh function header with: movl %edx, (%rsi) the parameter types / order; and • movswl %di, %edi the return type. • subl %edi, %ecx movl %ecx, %eax retq movsbl = mov e s ign-extending a b yte to a l ong (4-byte) movswl = mov e s ign-extending a w ord (2-byte) to a l ong (4-byte) x86 Procedures 29
Recommend
More recommend