Transcript Assembly 07
Assembly 07 Outline • • • • • • • • 1 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Boxes within Boxes • Procedures help manage code complexity • Procedures make code more: • Readable • Maintainable • Reusable 2 What does this code do again? Boxes within Boxes • Unlike high-level languages, assembly does not “ship” with built-in procedures (e.g., printf in C++) • You have to write your own procedures • Read from file • Write to file • Etc. 3 Boxes within Boxes • Book uses example of “getting up in the morning” • • • • • • 4 Shut off clock radio Climb out of bed Let dogs out Eat breakfast Brush your teeth Shower Boxes within Boxes • Each task can be divided into smaller tasks: • E.g., Brushing your teeth: • • • • Pick up toothpaste Unscrew cap Place cap on sink counter … • Same idea with procedures • Divide tasks into subtasks 5 Outline • • • • • • • • 6 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Procedure Definition • Must begin with a label • Must have at least one ret (return) • E.g., my_print: <instruction> <instruction> ret 7 ; label for “my_print” proc ; some instruction ; some instruction ; return Outline • • • • • • • • 8 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion call Mnemonic call -> used to invoke the procedure usage: call <procedure_name>; 9 ret Mnemonic ret usage: ret 10 -> ; ; returns from procedure takes no operands returns to instruction after call call / ret Mnemonics • call puts esp onto stack • esp has address of next instruction (after call) • ret pops esp from stack • Execution resumes at the instruction after call 11 stack 1. instruction executes my_print: <instruction>; <instruction>; ret; esp <instruction>; call my_print; 12 <next instr>; … stack 2. call to my_print made my_print: <instruction>; <instruction>; ret; <instruction>; esp 13 call my_print; <next instr>; … 3. esp+1 value pushed to stack stack address of <next instr>; my_print: <instruction>; <instruction>; ret; <instruction>; esp 14 call my_print; <next instr>; … 4. flow of execution goes to my_print stack address of <next instr>; my_print: esp <instruction>; <instruction>; ret; <instruction>; call my_print; 15 <next instr>; … 5. my_print executes stack address of <next instr>; my_print: <instruction>; esp <instruction>; ret; <instruction>; call my_print; 16 <next instr>; … 6. ret (return) reached in my_print stack address of <next instr>; my_print: <instruction>; <instruction>; esp ret; <instruction>; call my_print; 17 <next instr>; … stack 7. Address popped off stack address of <next instr>; 8. esp set to address my_print: <instruction>; <instruction>; esp ret; <instruction>; call my_print; 18 <next instr>; … 9. Flow of execution continues at instruction after call stack my_print: <instruction>; <instruction>; ret; <instruction>; call my_print; esp 19 <next instr>; … stack 10. Flow of execution continues… my_print: <instruction>; <instruction>; ret; <instruction>; call my_print; <next instr>; 20 esp … stack return address return address return address return address return address Every time you make a call, the stack grows by 32 bits. Why?? 21 stack return address return address return address Every time you return from a procedure (with ret), the stack shrinks by 32 bits. 22 msg: db “Hello There!!!”,10 msgLen: equ $-msg ; ; in .data in .data call my_print call my_print call my_print ; ; ; in .text in .text in .text my_print: mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, msgLen int 0x80 ret ; in .text ; make sys_write call ; write to stdout ; write contents of msg ; number of bytes to write ; make system call ; return call / ret Mnemonics UNIX> ./a.out Hello World!!! Hello World!!! Hello World!!! UNIX> 24 msg: db “Hello There!!!”,10 msgLen: equ $-msg call my_print call my_print call my_print my_print: mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, msgLen int 0x80 ret Outline • • • • • • • • 25 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Saving Register Values • What is the result of add eax, ebx? mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; 26 Saving Register Values mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; 27 eax ebx Saving Register Values mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; 28 eax 42 ebx 58 Saving Register Values mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; eax 4 ebx 1 my_print sets eax to “4” for sys_write my_print sets ebx to “1” for stdout 29 Saving Register Values mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; eax 5 ebx 1 were we expecting “5” or “100”?? 30 Saving Register Values • Often important to save registers before calling a procedure • Guards against bugs that are extremely hard to track down spooky 31 Saving Register Values • Use the stack to save registers • Push registers onto stack before procedure call • Pop registers off of stack after procedure returns • Be mindful of order! • Last In First Out 32 Saving Register Values • If you “own” the procedure code, you can push / pop registers within the procedure • Push registers at beginning of procedure • Pop registers at end of procedure 33 Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; 34 eax ebx Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; 35 eax 42 ebx 58 Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; 36 eax 42 ebx 58 all 32-bit GP registers pushed to stack Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; 37 eax 4 ebx 1 Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; 38 eax 42 ebx 58 pop all 32-bit registers from stack back to registers Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; 39 eax 100 ebx 58 Outline • • • • • • • • 40 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Passing Arguments • How do you pass arguments to assembly procedures? • … and no, this is not a setup for a hilarious joke… • Use registers! • Caller puts arguments into pre-ordained registers • E.g., eax is argument 1, ebx is argument 2, etc. • Important to clearly comment your procedures!! • Especially expectations for arguments • E.g., integer in eax, pointer in ebx, etc. 41 Passing Arguments • Example: procedure to add two numbers, print result to stdout • Numbers will be arguments to procedure • Simplified version: only prints results between 0 and 9… • Printing results > 10 may be part of your homework… 42 SIZE: equ 10 output: resb SIZE mov eax, 2 mov ebx, 3 call my_add ; in .data ; in .bss ; below in .text ; argument 1 in eax ; argument 2 in ebx ; invoke procedure to add/print my_add: ; procedure to add / print result add eax, ebx ; add arguments add eax, ‘0’ ; convert to ASCII number mov [output], eax; ; put result in output buffer mov byte [output+1], 10 ; add carriage return call my_print ; write output buffer to stdout ret ; return to caller Procedure Arguments UNIX> ./a.out 5 UNIX> msg: SIZE: equ 10 output: resb SIZE mov eax, 2 mov ebx, 3 call my_add my_add: add eax, ebx add eax, ‘0’ mov [output], eax mov byte [output+1], 10 call my_print ret 44 Outline • • • • • • • • 45 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Return Value(s) • How do you return value(s) from assembly procedures? • Register(s), of course!! • Example: convert character from lowercase to uppercase 46 mov al, ‘a’ call convert ; argument 1 in al ; convert ‘a’ to ‘A’ ; cl now has converted covert: mov cl, al sub cl, 32 ; procedure to convert ; copy argument 1 ; make return value uppercase ; (‘A’ is 32 less than ‘a’) ; return to caller ret mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret al cl mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret al cl 96 = 0x61 = ‘a’ mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret al cl 96 = 0x61 = ‘a’ mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret al 96 = 0x61 = ‘a’ cl 96 = 0x61 = ‘a’ mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret al 96 = 0x61 = ‘a’ cl 65 = 0x41 = ‘A’ mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret al 96 = 0x61 = ‘a’ cl 65 = 0x41 = ‘A’ now cl has return value ‘A’ Outline • • • • • • • • 54 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Global vs. Local Data • Global: can be accessed anywhere in code • Local: can only be accessed “locally” (e.g., within procedure) • In x86 assembly, all declared data items are global • Can declare data items in .text (!!!) • Appear local, but actually global 55 Examples of Local Data • Using the stack to temporarily store data in procedures • Data pushed to stack (during procedure) only visible to that procedure • Data items declared in external code libraries • Only visible to external code • (But there is a mechanism to make global) 56 Outline • • • • • • • • 57 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion Accidental Recursion • “Uncommon but inevitable bug” • Watch out for incorrect base case • Pay attention to instruction => flags • Will eventually run out of stack space • Each call pushes 32-bits onto stack (Why?) • Eventually causes a Segmentation Fault (Why?) 58 Accidental Recursion Example • “Not so accidental” recursion call recur; recur: call my_print “LINE” call recur ret 59 ; 1st instruction in .text ; after _start ; call procedure to print ; make recursive call ; never reached.. Accidental Recursion Example UNIX> ./a.out LINE LINE stdout in BLUE LINE stderr in GREEN LINE LINE ... (on and on..) Segmentation Fault UNIX> 60 call recur; recur: call my_print call recur ret Accidental Recursion Example UNIX> ./a.out > output.txt Segmentation Fault UNIX> head –n 2 output.txt LINE LINE UNIX> wc –l output.txt 2094543 output.txt 61 Accidental Recursion Example UNIX> ./a.out > output.txt Segmentation Fault UNIX> head –n 2 output.txt LINE LINE UNIX> wc –l output.txt 2094543 output.txt 62 > : redirect stdout to a file named “output.txt” stderr ignored Accidental Recursion Example UNIX> ./a.out > output.txt Segmentation Fault UNIX> head –n 2 output.txt LINE LINE UNIX> wc –l output.txt 2094543 output.txt 63 head –n 2 output.txt : output top 2 lines of file output.txt output.txt contains “LINE” printed once per line Accidental Recursion Example UNIX> ./a.out > output.txt Segmentation Fault UNIX> head –n 2 output.txt LINE LINE UNIX> wc –l output.txt 2094543 output.txt wc –l output.txt : count number of lines in file output.txt output.txt contains 2,094,543 lines. recur called 2+ million times!! 64