7- Indirect Addressing, MASM Procedures, and System Stack Flashcards
What is indirect addressing?
Using a register as a pointer and then manipulating the register’s value.
How can you do indirect addressing?
You can use any 32-bit general purpose register (EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP). Since ESI contains the offset of byteVal, you can move al to byteVal’s memory location.
.data byteVal BYTE 10h .code mov esi, OFFSET byteVal mov al, [esi] ;AL = 10h
What happens if the destination operand uses indirect addressing?
Then whatever is from the source will be copied to the destination. For example, this will copy whatever’s in BL into whatever address is stored in esi.
mov [esi], bl
How can you use indirect operands for stepping through arrays?
You simply point to the address and then add the size of each element to esi.
.data arrayW WORD 1000h, 2000h, 3000h .code mov esi, OFFSET arrayW mov ax, [esi] ;AX = 1000h add esi, 2 mov ax, [esi] ;AX = 2000h add esi, 2 mov ax, [esi] ;AX = 3000h
What are indexed operands and how do you use them?
constant[reg]
[constant + reg]
An indexed operand adds a constant to any of the 32-bit registers to generate an effective address.They are great for array processing as long as the index register is initialized to zero.
.data arrayB BYTE 10h, 20h, 30h .code mov esi, 0 mov al, arrayB[esi] ;AL = 10h
How do you add displacements to indexed operands?
You just add the size of the element to the register within the indexed operand.
.data arrayW WORD 1000h, 2000h, 3000h .code mov esi, OFFSET arrayW mov ax, [esi] ;AX = 1000h mov ax, [esi+2] ;AX = 2000h mov ax, [esi+4] ;AX = 3000h
Can you use 16-bit registers as indexed operands?
In real-address mode, it is usual to do so (in protected, you use 32-bit ones). However, that means you are limited to using SI, DI, BX, or BP (try to only use BP when addressing data on the stack)
mov al, arrayB[si]
mov ax, arrayW[di]
mov eax, arrayD[bx]
How is TYPE used to compensate for element sizes in indexed operands?
You can multiply the subscript the size of the element using TYPE.
.data
arrayD DWORD 100h, 200h, 300h, 400h
mov esi, 3 * TYPE arrayD ;offset of arrayD[3]
mov eax, arrayD[esi] ;EAX = 400h
What is a scale factor and how is it used?
Instead of using TYPE, Intel designers wanted to just allow direct scale factors for each element (word = 2, doubleword = 4, quadword = 8).
.data arrayD DWORD 1, 2, 3, 4 ,code mov esi, 3 ;subscript mov eax,arrayD[esi*4] ;EAX =4
How do you use pointers in MASM?
You can either just say “variable type variable “ or make it more clear by saying “variable type OFFSET variable”.
.data
arrayB byte 10h, 20h, 30h, 40h
ptrB dword arrayB
OR
ptrB dword OFFSET arrayB
How do you use the TYPEDEF operator?
It lets you create a user-defined type that has all the status of a built-in type when defining variables. It is ideal for creating pointer variables (this creates a new data type PBYTE that is a pointer to bytes).
PBYTE TYPEDEF PTR BYTE
.data
arrayB BYTE 10h, 20h, 30h, 40h
ptr1 PBYTE ? ;uninitialized
ptr2 PBYTE arrayB ;points to an array
What is an example of a TYPEDEF usage?
PBYTE TYPEDEF PTR BYTE
.data
arrayB BYTE 10h, 20h, 30h
ptr1 BYTE arrayB
.code main PROC mov esi, ptr1 mov al, [esi] ;10h invoke ExitProcess, 0 main ENDP
Can any 32-bit general purpose register be used as an indirect operand?
Yes.
Is the EBX register usually reserved for addressing the stack?
No, it’s the ESP register.
Is the following instruction valid?
inc [esi]
No, you’d have to just say inc esi.
Is the following an indexed operand?
array[esi]
Yes, just the first element in the array (as long as esi were 0)
What are subroutines called in C/C++ and MASM?
What are the values passed to a subroutine called?
In C/C++, they’re called functions. In MASM, they’re called procedures.
The values passed to them are called arguments, and when the values are received by the subroutine, they’re called parameters.
What type of parameters do subroutines receive on the runtime stack in 32-bit mode?
In 32-bit mode, stack parameters are always used (as opposed to the register parameters we’ve been using).
What is the stack frame (or activation record)?
The area of the stack set aside for passed arguments, subroutine return address, local variables, and saved registers.
How is the stack frame created?
- Passed arguments, if any, are pushed onto the stack
- The subroutine is called, causing the subroutine return address to be pushed onto the stack.
- As the subroutine begins to execute, EBP is pushed on the stack.
- EBP is set equal to ESP. From this point on, EBP acts as a base reference for all of the subroutine parameters.
- If there are local variables, ESP is decremented to reserve space for the variables on the stack.
- If any registers need to be saved, they are pushed on the stack.
What were the disadvantages of register parameters?
For years, Microsoft included a parameter passing convention named fastcall (efficiency by placing parameters in registers). However, these ALSO are used to hold data values such as loop counters and operands in calculations.
Therefore, any registers used as parameters must be pushed on the stack before procedure calls, assigned the values of procedure arguments, and later restored to their original values after the procedure returns. This ends up being SLOWER and requires being careful that each register’s PUSH is matched by the appropriate POP.
How do stack parameters fix this problem?
Just before a subroutine call, the arguments are pushed onto the stack (either value arguments or reference arguments). For example, if DumpMem used stack parameters, we would call it using the following code.
push TYPE array
push LENGTHOF array
push OFFSET array
call DumpMem
How can you pass by value?
A copy of the value is pushed onto the stack.
.data val1 DWORD 5 val2 DWORD 6 .code push val2 push val1 call AddTwo
The stack would look like this:
(val2) - 6
(val1) - 5
How can you pass by reference?
An argument passed by reference consists of the address of an object. The following arguments call Swap, passing the two arguments by reference:
push OFFSET val2
push OFFSET val1
call Swap
offset(val2)
offset(val1)
How can you pass arrays?
You can just pass the address of the array. For example, this will pass the offset of an array to a subroutine named ArrayFill
.data array DWORD 50 DUP(?) .code push OFFSET array call ArrayFill
How do high-level languages like C/C++ initialize and access parameters during function calls?
They begin with a prologue consisting of statements that save the EBP register and point EBP to the top of the stack. (OR, they push certain registers on the stack whose values will be restored when the function returns).
The end of the function is an epilogue in which the EBP register is restored and RET instruction returns to the caller.
What would this AddTwo function in C look like in assembly language?
int AddTwo(int x, int y) { return x + y; }
In the prologue, AddTwo pushes EBP on the stack to preserve its value. Then, EBP is set to ESP so that ESP can be the base pointer for the stack frame.
AddTwo PROC
push ebp
mov ebp, esp
If you did AddTwo(5, 6), then the stack would look like: 6 -- [EBP+12] 5 -- [EBP+8] return address --{EBP+4] EBP
What are explicit stack parameters?
When stack parameters are referenced with expressions like [ebp+8]. Some programmers define symbolic constants to represent the explicit stack parameters to make their code easier to read:
y_param EQU [ebp + 12]
x_param EQU [ebp + 8]
AddTwo PROC push ebp mov ebp, esp mov, eax, y_param add, eax, x_param pop ebp ret AddTwo ENDP
Why is it necessary to clean the runtime stack?
Otherwise, you would at least have a memory leak and at worst have a corrupted stack. For example, the AddTwo procedure might leave this on the stack:
return address
6
5
What are the two major 32-bit calling conventions?
The C calling convention and the STDCALL calling convention. Both are used on Windows, and both help to clear the stack.
What is the C calling convention?
Subroutine parameters are pushed on the stack in reverse order. Then, when a program calls a subroutine, it follows the CALL instruction with a statement that adds a value to the ESP equal to the combined sizes of the subroutine parameters.
Example1 PROC push 6 push 5 call AddTwo add esp, 8 ret Example1 ENDP
What is the STDCALL Calling Convention?
Like C, it pushes arguments on the stack in reverse order. It also supplies an integer parameter to the RET instruction, which adds 8 to ESP after returning to the calling procedure. It must equal the number of bytes of stack space consumed by the procedure’s parameters.
AddTwo PROC push ebp mov ebp, esp mov eax, [ebp + 12] add eax, [ebp + 8] pop ebp ret 8 AddTwo ENDP
Therefore, programs always remove arguments from the stack in the calling program AFTER a subroutine has returned.
What are some major differences between the C calling convention and the STDCALL calling convention?
By having a parameter in the RET instruction, STDCALL reduces the amount of code for subroutine calls and ensures that they never forget to clean up the stack.
On the other hand, the C calling convention permits subroutines to declare a variable number of parameters. The caller can decide how many arguments it will pass.
For example, the printf function number of arguments depend on the number of format specifiers (e.g. %d). The function implementation has no convenient way of encoding a constant in the RET instruction to clean up the stack, so it’s up to the caller.
Why do you save and restore registers?
Subroutines often save the current contents of registers on the stack before modifying them because they can restore the original values just before the subroutine returns.
How do you save and restore registers?
Assume that mySub procedure has one stack parameter. It pushes ECX and EDX after setting EBP to the base of the stack frame and loads the stack parameter into EAX.
MySub PROC push ebp ;save base pointer mov ebx, esp ;base of stack frame push ecx push edx mov eax, [ebp + 8] ;get the stack parameter . . pop edx ;restore saved registers pop ecx ;restore base pointer pop ebp ;clean up the stack ret MySub ENDP
After it’s initialized, EBP’s contents are fixed. Pushing ECX and EDX don’t affect displacement from EBP because the stack grows below EBP.
(parameter) [EBP +8]
return address [EBP + 4]
EBP
How are local variables created?
They are created on the runtime stack, usually below the base pointer (EBP). For example, the following function would allocate local variables:
void MySub() { int x = 10; int y = 20; }
x would be EBP - 4
y would be EBP - 8
How does would the C calling convention create the local variables in this program?
void MySub() { int x = 10; int y = 20; }
MySub PROC push ebp mov ebp, esp sub esp, 8 ;create locals mov DWORD PTR [ebp-4], 10 ;x mov DWORD PTR [ebp-8], 20 ;y mov esp, ebp ;remove locals from the stack pop ebp ret MySub ENDP
WATCH OUT!! If you don’t include the mov esp, ebp (resetting the stack pointer by assigning it the value of EBP), then RET will return to an invalid address!!
How are reference parameters usually accessed?
By procedures using base-offset addressing from EBP. If a pointer to an array is located at stack address [ebp+12], statement will copy the pointer into ESI:
mov esi, [ebp+12] ;points to the array.
What is an input parameter?
An input parameter is data passed by a calling program to a procedure.
The called procedure is NOT expected to modify the corresponding argument variable, and even if it does, the modification is confined to the procedure.
What is an output parameter?
An output parameter is created by passing the address of an argument variable when a procedure is called.
The “address of” a variable is the same as OFFSET. The value is NOT used in th calculation in the procedure.
What is an input-output parameter?
The address of an argument variable that contains input that will both be USED AND MODIFIED by the procedure.
What are the methods of passing among procedures?
- Use shared memory (global variables)
- Pass parameters in registers
- Pass parameters on the system stack
What’s good and bad about global variables?
Generally, it’s BAD because the procedure might change memory contents needed by other procedures!! There’s NO clear interface between any two procedures.
What’s good/bad about passing through registers?
Generally, it’s BAD again because the procedure might change register contents!!
However, some Irvine library procedures require values in registers (b/c these are easier).
What’s good/bad about passing parameters on the system stack?
The calling procedure is required to push these onto the stack before the call, but the call places the return addresses on the top of the stack, making it inaccessible. So, you have to remove the parameters and return to the calling program.
However, it’s much more efficient because you don’t have to save and then renew the previous values.
On the other hand, some “setup” is involved in the calling procedure and some “bookkeeping” is involved in the called procedure.