5 - Procedures Flashcards
What is the runtime stack?
A memory array managed directly by the CPU, using the ESP (extended stack pointer) register. We rarely manipulate ESP directly - usually we used instructions like CALL, RET, PUSH, and POP.
ESP always points to the last value to be added to, or pushed on, the top of the stack. (e.g. if ESP = 00001000h, then the address 0001000 holds the only value of the stack.
How does a push operation work?
PUSH reg/mem16 (-2 ESP)
PUSH reg/mem32 (-4 ESP)
PUSH imm32
It decrements the stack pointer and places the next value at the next lowest address.
00001000 - 00000006 - ESP
00000FFC
00000FF8
00001000 - 00000006
00000FFC - 000000A5 - ESP
00000FF8
How does a pop operation work?
POP reg/mem16
POP reg/mem32
It removes a value from the stack, increments the ESP, and removes the last value.
00001000 - 00000006
00000FFC - 000000A5 - ESP
00000FF8 - 00000001 - ESP
00000FF0
00001000 - 00000006
00000FFC - 000000A5 - ESP
00000FF8
What are the uses of runtime stacks in programs?
- A temporary save area for registers when they are used for more than one purpose. After they are modified, they can be restored.
- When the CALL instruction executes, the CPU saves the current subroutine’s return address on the stack.
- When calling a subroutine, you pass input values called arguments by pushing them on the stack.
- The stack provides temporary storage for local variables inside subroutines.
What do the PUSHFD and POPFD instructions do?
PUSHFD pushes the EFLAGS register onto the stack, and POPFD pops the stack into EFLAGS.
You use these because the MOV instruction cannot be used to copy the flags to a variable. Therefore, you can just use this to save to a variable:
pushfd
pop saveflags
And use this to restore from the same variable
push saveFlags
popfd
How can you use the PUSHAD /POPAD or PUSHA/POPA instructions?
PUSHAD pushes all the 32-bit general purpose registers onto the stack in this order (EAX, ECX, EDX, EBX, ESP (value before), EBP, ESI, and EDI). POPAD pops them off in reverse order.
PUSHA and POPA are the same for 16-bit registers (AX, CX, DX, BX, SP, BP, SI, DI).
When do you use PUSHAD and POPAD?
Generally, if you write a procedure that modifies a number of 32-bit registers, use PUSHAD at the beginning of the procedure and POPAD at the end to save and restore the registers.
pushad ; save general-purpose registers . .mov eax, .... mov edx, ... mov ecx, ... . popad ; restore general-purpose registers ret
When do you not want to use PUSHAD and POPAD?
When you actually care about the results after you PUSHAD. For example, if you put a return value into EAX, you don’t want that instruction the middle of pushad and popad, which will overwrite it.
How can you reverse a a string using the stack?
Put the size of the name in ECX, put each character (using ESI=0 as your index) into a register and push that onto the stack, increment ESI, and loop back until it’s a null character.
mov ecx, nameSize mov esi, 0 L1: movzx eax, aName[esi] push eax inc esi loop L1
Then, you can put the size of the name in ECX (using ESI=0 as your index), pop eax to get the character, and mov everything from al into the same character array, incrementing ESI each time.
mov ecx, nameSize mov esi, 0 L2: pop eax mov aName[esi], al inc esi loop L2
Which register manages the stack?
ESP
When a 32-bit value is pushed on the stack, what happens to ESP?
ESP is decremented by 4.
It is true or false that local variables in procedures are created on the stack?
True.
Is it true or false that the PUSH instruction cannot have an immediate operand?
False - you can definitely push just a value.
What is a procedure?
Generally, it’s a subroutine (in higher-level languages, they’re just methods or functions).
How do you define a procedure?
You use the PROC and ENDP directives. Whenever you create a procedure other than your program’s startup procedure, you MUST end it with the RET instruction, which forces the CPU to return to the location where the procedure was.
sample PROC
…
ret
sample ENDP
What are labels in procedure?
By default, labels are visible only within the procedure in which they are declared. WATCH OUT! This can be a problem when you have jmp and loop instructions (the label after JMP MUST be located in the same procedure as the JMP instruction).
You can work around this limitation by declaring a global label, with (::) after its name
(e.g. Destination::). However, it’s not a good idea to jump or loop outside the current procedure because the runtime stack may become corrupted.
How can you create a PROC that calculates the sum of three 32-bit integers?
The following code returns the sum of EAX, EBX, and ECX in EAX.
SumOf PROC add eax, ebx add eax, ecx ret SumOf ENDP
What kind of comments should you put at the beginning of each procedure?
A description of all tasks accomplished, a list of input parameters and their uses (e.g. Receives…), description of any values returned (e.g. Returns…), and any preconditions (e.g. Requires…).
;———————————–
; sumof
;
; Calculates and returns the sum of 32-bit integers.
; Receives: EAX, EBX, ECX, the three integers. May be signed or unsigned.
; Returns: EAX = sum
———————————–
How are the CALL and RET instructions used?
The CALL instruction calls a procedure by directing the processor to begin execution at a new memory location. The procedure uses a RET (return from procedure) instruction to bring the processor back to the point in the program where the procedure was called.
The CALL instruction pushes its return address on the stack and copies the called procedure’s address into the instruction pointer. When the procedure is ready to return, the RET instruction pops the return address from the stack into the instruction pointer. In 32-bit mode, the CPU executes the instruction in memory pointed to by EIP.
What happens to the stack, EIP, and ESP in the following instructions (at the following offsets)?
main PROC
00000020 - call MySub
00000025 - mov eax, ebx
MySub PROC 00000040 - mov eax, edx .... ret MySub ENDP
When the CALL instruction executes, the address following the call (00000025) is pushed onto the stack and the address of MySub is loaded into EIP. All instructions in MySub execute up to its RET instruction.
When the RET instruction executes, the value in the stack pointed to by ESP is popped into EIP. Then, ESP is incremented so it points to the previous value on the stack.
How can you make nested procedure calls?
Main calls a procedure named sub1, which calls procedure sub2.
When the RET instruction at the end of sub2 is about to execute, the stack looks like:
(ret to main)
(ret to sub1) - ESP
When sub1 returns, stack[ESP] is popped into the instruction pointer, and execution resumes in main.
(ret to main) - ESP