CIS-77 Home http://www.c-jump.com/CIS77/CIS77syllabus.htm
A stack is an area of memory for storing data temporarily.
Unlike other segments that store data starting from low memory, the stack stores data starting from high memory.
The data is said to be pushed onto, and popped from the top of the stack.
The stack gets its name from its similarity to the spring-loaded plate holders in cafeterias: you add and remove plates from only the top of the stack.
To retrieve the third plate, you must remove (pop) the first two plates.
Stacks are often referred to as LIFO buffers, from their last-in-first-out operation.
A program continually uses its stack to temporarily store and preserve return addresses, procedure arguments, memory data, flags, and registers.
The stack is assembled as uninitialized segment of a finite size.
For example, the .STACK directive
.STACK 4096
tells the assembler to reserve 4096 bytes of uninitialized storage.
The operating system initializes ESP to the address of the first byte above the 4096 bytes in the stack.
A larger or smaller stack could be allocated, depending on the anticipated usage in the program.
The PUSH instruction stores its operand on the stack.
The POP instruction retrieves the most recent pushed value.
ESP register always points to the top of the stack.
The PUSH and POP instructions use the ESP register to keep track of the current position.
The operand can be a register 16, a register 32, a segment register, a word in memory, a doubleword in memory, an immediate byte, an immediate word, or an immediate doubleword.
It is impossible to push an 8-bit item onto the stack.
When an immediate byte-size operand is pushed, multiple bytes are pushed on the stack accordingly to the current mode:
In 16-bit modes stack items are WORD-size (2 bytes) at address SS:SP.
In 32-bit modes the top of the stack is the DWORD addressed by [ ESP ].
Execution of PUSH AX instruction:
The ESP register serves as an indirect memory operand pointing to the top of the stack at any time.
As program adds data to the stack, the stack grows downward from high memory to low memory.
When items removed from the stack, stack shrinks upward from low to high memory.
When a word value is pushed onto the stack, the assembler decreases the ESP (Stack Pointer) register by 2.
When a word value is popped off the stack, the assembler increases the ESP register by 2.
When a double word value is pushed/popped off the stack, the assembler decreases/increases the ESP register by 4.
Thus, ESP register changes in multiples of two or four.
If there is ambiguity about the size of the operand (as would be with a small immediate value), then you can use PUSHW or PUSHD mnemonics to specify a word or doubleword size operands, respectively.
For example the following two instructions are the same:
push dword -240 pushd -240
If operand is immediate value, such as single byte -240, is stored in the instruction, it is sign-extended to a doubleword that is actually stored on the stack.
The byte-size operand results in a smaller instruction, but does not reduce stack space consumption at execution time.
No PUSH or POP instruction affects any flag bits.
There is a separate pair of instructions, PUSHF and POPF, for pushing and popping the EFLAGS register.
Execution of PUSHD and PUSHW instructions:
pushw 1000h pushd eax
Values are popped off the stack in reverse order: the last item pushed is the first popped.
To return the stack to its original status, you do the same number of pops as pushes.
You can subtract the correct number of words from the ESP register if you want to restore the stack without using the values on it.
Sample code: show_ESP.asm
Execution of POP BX
To reference operands on the stack, remember that the values pointed to by the EBP (Base Pointer) and ESP registers are relative to the SS (Stack Segment) register.
The EBP register is often used to point to the base of a frame of reference (a stack frame) within the stack.
This example shows how you can access values on the stack using indirect memory operands with 16-bit BP as the base register.
push bp ; Save current value of BP mov bp, sp ; Set stack frame push ax ; Push first; SP = BP - 2 push bx ; Push second; SP = BP - 4 push cx ; Push third; SP = BP - 6 . . . mov ax, [bp-6] ; Put third word in AX mov bx, [bp-4] ; Put second word in BX mov cx, [bp-2] ; Put first word in CX . . . add sp, 6 ; Restore stack pointer ; (two bytes per push) pop bp ; Restore BP
Program can push and pop flags onto the stack with the PUSHF and POPF instructions.
These instructions save and then restore the status of the flags.
Program can also use PUSHF and POPF around procedure calls to preserve flag status of the caller.
The 32-bit versions of these instructions are PUSHFD and POPFD.
This example saves the flags register before calling the systask procedure:
pushfd call systask popfd
If you do not need to store the entire flags register, you can use the LAHF instruction to manually load and store the status of the lower byte of the flag register in the AH register. SAHF restores the value.
Operation of PUSHF
PUSHA and POPA instructions push or pop all 16-bit general-purpose registers with only one instruction.
These instructions save the status of all registers before a procedure call and restore them after the return.
Using PUSHA and POPA is significantly faster and takes fewer bytes of code than pushing and popping each register individually.
The processor pushes the registers in the following order: AX, CX, DX, BX, SP, BP, SI, and DI. The SP word pushed is the value before the first register is pushed.
The processor pops the registers in the opposite order.
The 32-bit versions of these instructions are PUSHAD and POPAD.
Order of registers pushed with PUSHA and PUSHAD instructions:
Order of registers popped with POPA and POPAD instructions
Loading all GP registers with POPA