Assembly 07
Outline Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 1
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” Shut off clock radio Climb out of bed Let dogs out Eat breakfast Brush your teeth Shower 4
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 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 6
Procedure Definition Must begin with a label Must have at least one ret (return) E.g., my_print:; label for “my_print” proc ; some instruction ret; return 7
Outline Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 8
call Mnemonic call ->used to invoke the procedure usage: call ; 9
ret Mnemonic ret->returns from procedure usage: ret;takes no operands ; returns to instruction after call 10
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
12 my_print: ; ret; ; call my_print; ; … stack esp 1. instruction executes
13 my_print: ; ret; ; call my_print; ; … stack esp 2. call to my_print made
14 my_print: ; ret; ; call my_print; ; … stack esp 3. esp+1 value pushed to stack address of ;
15 my_print: ; ret; ; call my_print; ; … stack esp 4. flow of execution goes to my_print address of ;
16 my_print: ; ret; ; call my_print; ; … stack 5. my_print executes address of ; esp
17 my_print: ; ret; ; call my_print; ; … stack 6. ret (return) reached in my_print address of ; esp
18 my_print: ; ret; ; call my_print; ; … stack 7. Address popped off stack 8. esp set to address address of ; esp
19 my_print: ; ret; ; call my_print; ; … stack 9. Flow of execution continues at instruction after call esp
20 my_print: ; ret; ; call my_print; ; … stack 10. Flow of execution continues… esp
21 stack Every time you make a call, the stack grows by 32 bits. Why?? return address
22 stack Every time you return from a procedure (with ret), the stack shrinks by 32 bits. return address
msg: db “Hello There!!!”,10;in.data msgLen: equ $-msg; in.data call my_print;in.text my_print:; in.text mov eax, 4; make sys_write call mov ebx, 1; write to stdout mov ecx, msg; write contents of msg mov edx, msgLen; number of bytes to write int 0x80; make system call ret; return
call / ret Mnemonics UNIX>./a.out Hello World!!! UNIX> 24 msg: db “Hello There!!!”,10 msgLen: equ $-msg call my_print my_print: mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, msgLen int 0x80 ret msg: db “Hello There!!!”,10 msgLen: equ $-msg call my_print my_print: mov eax, 4 mov ebx, 1 mov ecx, msg mov edx, msgLen int 0x80 ret
Outline Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 25
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; eax ebx
Saving Register Values mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; eax ebx my_print sets eax to “4” for sys_write my_print sets ebx to “1” for stdout
Saving Register Values mov eax, 42; mov ebx, 58; call my_print; add eax, ebx; eax ebx were we expecting “5” or “100”??
Saving Register Values Often important to save registers before calling a procedure Guards against bugs that are extremely hard to track down 31 spooky
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; eax ebx
Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; eax ebx 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; eax ebx
Saving Register Values mov eax, 42; mov ebx, 58; pushad; call my_print; popad; add eax, ebx; eax ebx 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; eax ebx
Outline Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 40
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; in.data output: resb SIZE ; in.bss ; below in.text mov eax, 2; argument 1 in eax mov ebx, 3; argument 2 in ebx call my_add; 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 44 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 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
Outline Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 45
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’; argument 1 in al call convert; convert ‘a’ to ‘A’ ; cl now has converted covert:; procedure to convert mov cl, al; copy argument 1 sub cl, 32; make return value uppercase ; (‘A’ is 32 less than ‘a’) ret; return to caller
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 96 = 0x61 = ‘a’ al cl
mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret 96 = 0x61 = ‘a’ al cl
mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret 96 = 0x61 = ‘a’ al cl
mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret 96 = 0x61 = ‘a’ 65 = 0x41 = ‘A’ al cl
mov al, ‘a’; call convert; covert: mov cl, al sub cl, 32 ret 96 = 0x61 = ‘a’ 65 = 0x41 = ‘A’ al cl now cl has return value ‘A’
Outline Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 54
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 Boxes within Boxes Procedure Definition call, ret Saving / Restoring Registers Argument(s) Return Value(s) Global vs. Local Data Accidental Recursion 57
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;; 1st instruction in.text ; after _start recur: call my_print; call procedure to print “LINE” call recur; make recursive call ret; never reached.. 59
Accidental Recursion Example UNIX>./a.out LINE... (on and on..) Segmentation Fault UNIX> 60 call recur; recur: call my_print call recur ret call recur; recur: call my_print call recur ret stdout in BLUE stderr in GREEN
Accidental Recursion Example UNIX>./a.out > output.txt Segmentation Fault UNIX> head –n 2 output.txt LINE UNIX> wc –l output.txt output.txt 61
Accidental Recursion Example UNIX>./a.out > output.txt Segmentation Fault UNIX> head –n 2 output.txt LINE UNIX> wc –l output.txt 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 UNIX> wc –l output.txt 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 UNIX> wc –l output.txt output.txt 64 wc –l output.txt : count number of lines in file output.txt output.txt contains 2,094,543 lines. recur called 2+ million times!!