Procedures and the Call Stack the Call Stack Discipline X86 Procedure Call and Return Instructions X86 Calling Conventions X86 Register-Saving Conventions
Total Page:16
File Type:pdf, Size:1020Kb
CS 240251 SpringFall 2019 2020 FoundationsPrinciples of Programming of Computer Languages Systems λ 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 yoo(…) { who • • • who(); • • • } who(…) { yoo: • • • 1 2 who: • • • jmp who back: 5 3 • • • } 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 yoo(…) { who • • • who(); ru ru • • • } who(…) { who: • • • 1 ru(); 2 ru: • • • jmp ru back2: 6 ru(); 5 3,7 • • • } jmp ru 4 back2: ru(…) { 9 jmp back2 • • • 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 Memory Layout reminder Addr Perm Contents Managed by Initialized N 2 -1 Stack RW Procedure context Compiler Run-time Programmer, Dynamic RW malloc/Free, Run-time Heap data structures new/GC Global variables/ Compiler/ RW Startup Statics static data structures Assembler/Linker Compiler/ R String literals Startup Literals Assembler/Linker Compiler/ X Instructions Startup Text 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 { • yooyoo who • %rsp who(); • amI amI • } amI amI x86 Procedures 9 Call stack tracks context Stack yoo(…) yoo { who(…) •{ yooyoo who • • • • who();amI(); • • • • amI amI who • amI(); %rsp } • • • } amI amI x86 Procedures 10 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • •{ • • who();amI();• • • •if( • …){ amI amI who • amI();amI() } • •} • } • amI amI } %rsp amI x86 Procedures 11 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • •{ •amI • (…) who();amI{();• • • •if( • …•){ amI amI who • amI();amIif(()…){ } • •} • amI() } •} amI amI } • } amI amI %rsp x86 Procedures 12 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • •{ •amI • (…) who();amI{();•amI(…) • • •if( •{…•){ amI amI who • amI();amIif(()…•){ } • •} • amIif(()…){ } •} amI() amI amI } •} } • amI } amI amI %rsp x86 Procedures 13 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • •{ •amI • (…) who();amI{();•amI(…) • • •if( •{…•){ amI amI who • amI();amIif(()…•){ } • •} • amIif(()…){ } •} amI() amI amI } •} } • amI } amI amI %rsp x86 Procedures 14 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • •{ •amI • (…) who();amI{();• • • •if( • …•){ amI amI who • amI();amIif(()…){ } • •} • amI() } •} amI amI } • } amI amI %rsp amI x86 Procedures 15 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • •{ • • who();amI();• • • •if( • …){ amI amI who • amI();amI() } • •} • } • amI amI } %rsp amI amI amI x86 Procedures 16 Call stack tracks context Stack yoo(…) yoo { who(…) •{ yoo yoo who • • who();amI(); • • amI amI who • amI(); %rsp } • } amI amI amI amI amI x86 Procedures 17 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • {• who();amI();• • • if(){ amI amI who • amI();amI() } • } } • amI amI } %rsp amI x86 Procedures 18 Call stack tracks context Stack yoo(…) yoo { who(…) •{ amI(…) yooyoo who • {• who();amI();• • • if(){ amI amI who • amI();amI() } • } } • amI amI } %rsp amI x86 Procedures 19 Call stack tracks context Stack yoo(…) yoo { who(…) •{ yooyoo who • • who();amI(); • • amI amI who • amI(); %rsp } • } amI amI amI x86 Procedures 20 Call stack tracks context Stack yoo(…) yoo { • yooyoo who • %rsp who(); • amI amI who • } amI amI amI x86 Procedures 21 The call stack supports procedures. Stack frame: section oF stack Saved Registers used by one procedure call to store context while running. Caller Local Variables Frame higher Extra Arguments addresses Procedure code manages to callee stack frames explicitly. Return Address • Setup: allocate space where to continue on return at start oF procedure. • Cleanup: deallocate space stack grows beFore return. Callee 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>: 0x7fdf20 0x400544 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 %rsp %rip 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>: 0x7fdf18 0x400557 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 %rsp %rip 0x7fdf20 0x400549 x86 Procedures 26 Procedure data flow conventions First 6 arguments: Remaining arguments: passed in registers passed on stack (in memory) Arg 1 %rdi High Diane’s • • • Addresses Arg 2 %rsi Silk Dress Arg n Arg 3 %rdx Costs Arg 4 %rcx $8 9 • • • Arg 5 %r8 Arg 8 Arg 6 %r9 Arg 7 Low Return Address Addresses Return value: Allocate stack space For arguments passed in %rax only when needed. %rax x86 Procedures 27 callq puzzle optional 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 Procedure data flow puzzle ex C function body: huh( , , , ) { *p = d; return x - c; } Translated to x86 assembly: huh: Reverse engineer the x86 huh procedure movsbl %dl, %edx and the body oF the C huh function to fill huh movl %edx, (%rsi) blanks in the C function header with: • the parameter types / order; and movswl %di, %edi • the return type. subl %edi, %ecx movl %ecx, %eax retq movsbl = move sign-extending a byte to a long (4-byte) movswl = move sign-extending a word (2-byte) to a long (4-byte) x86 Procedures 29 Procedure data flow puzzle ex C function body: int huh(short c, int* p, char d, int x) { *p = d; return x - c; } Translated to x86 assembly: huh: Reverse engineer the x86 huh procedure movsbl %dl, %edx and the body oF the C huh function to fill huh movl %edx, (%rsi) blanks in the C function header with: • the parameter types / order; and movswl %di, %edi • the return type. subl %edi, %ecx movl %ecx, %eax retq movsbl = move sign-extending a byte to a long (4-byte) movswl = move sign-extending a word (2-byte) to a long (4-byte) x86 Procedures 30 Procedure call / stack frame example long step_up() { long v1 = 240; step_up: long v2 = increment(&v1, 61); 400509: subq $8, %rsp return v1+v2; 40050d: movq $240, (%rsp) } 400515: movq %rsp, %rdi 400518: movl $61, %esi Passes address oF local variable (in stack). 40051d: callq 4004cd <increment> 400522: addq (%rsp), %rax 400526: addq $8, %rsp 40052a: retq Uses memory through pointer. long increment(long* p, long val) { long x = *p; long y = x + val; increment: *p = y; 4004cd: movq (%rdi), %rax return x; 4004d0: addq %rax, %rsi } 4004d3: movq %rsi, (%rdi) 4004d6: retq x86 Procedures 31 main called step_up Procedure call example (step 0) Stack long step_up() { Frames Memory long v1 = 240; long v2 = increment(&v1, 61); • • • return v1+v2; } 0x40053b main 0x7fdf28 step_up: <main+8> 400509: subq $8, %rsp 40050d: movq $240, (%rsp) 0x7fdf20 400515: movq %rsp, %rdi 400518: movl $61, %esi 0x7fdf18 40051d: callq 4004cd <increment> 400522: addq (%rsp), %rax 400526: addq $8, %rsp 40052a: retq %rax %rdi %rsi increment: 4004cd: movq (%rdi), %rax 4004d0: addq %rax, %rsi %rsp %rip 4004d3: movq %rsi, (%rdi) 0x7fdf28 0x400509 4004d6: retq x86 Procedures 36 Allocate space Procedure call example (step 1) for local vars Stack long step_up() { Frames Memory long v1 = 240; long v2 = increment(&v1, 61); • • • return