8086 Stack Operations and Procedures

Master the 8086 stack mechanism, understand procedure calls and returns, learn parameter passing techniques, and practice with real-world programming examples.

Stack Fundamentals in 8086

The stack is a Last In First Out (LIFO) data structure used for temporary storage, procedure calls, and interrupt handling. In 8086, the stack grows downward in memory.

Loading diagram...

Stack Registers:

  • SS (Stack Segment): 16-bit register pointing to stack segment
  • SP (Stack Pointer): 16-bit offset within stack segment
  • BP (Base Pointer): 16-bit pointer for stack frame access

Stack Physical Address:


Stack Physical Address = (SS × 16) + SP

Example:
If SS = 3000H and SP = 2000H
Stack Address = (3000H × 16) + 2000H = 30000H + 2000H = 32000H

Basic Stack Operations

PUSH Operation

PUSH instruction stores data on stack and decrements SP by 2 (for word data).


PUSH AX         ; Push AX register onto stack
PUSH 1234H      ; Push immediate value onto stack  
PUSH [BX]       ; Push memory content onto stack
PUSH CS         ; Push segment register onto stack

Operation Steps:
1. SP = SP - 2 (decrement stack pointer)
2. [SS:SP] = Source data (store data at new top)

POP Operation

POP instruction retrieves data from stack and increments SP by 2.


POP AX          ; Pop stack top into AX register
POP [BX]        ; Pop stack top into memory location
POP DS          ; Pop stack top into segment register

Operation Steps:
1. Destination = [SS:SP] (retrieve data from top)
2. SP = SP + 2 (increment stack pointer)
Loading diagram...

Stack Example:


Initial: SS = 2000H, SP = 1000H, AX = 1234H, BX = 5678H

PUSH AX:
- SP becomes 0FFEH (1000H - 2)
- Memory[2FFEH] = 34H, Memory[2FFFH] = 12H (little endian)

PUSH BX:  
- SP becomes 0FFCH (0FFEH - 2)
- Memory[2FFCH] = 78H, Memory[2FFDH] = 56H

POP CX:
- CX = 5678H (BX value retrieved)
- SP becomes 0FFEH (0FFCH + 2)

POP DX:
- DX = 1234H (AX value retrieved)  
- SP becomes 1000H (back to original)

Procedure Calls and Returns

CALL Instruction

CALL instruction transfers control to a procedure and saves return address on stack.

Types of CALL:


CALL NEAR PTR procedure_name    ; Near call (within same segment)
CALL FAR PTR procedure_name     ; Far call (different segment)
CALL BX                         ; Indirect near call
CALL DWORD PTR [BX]            ; Indirect far call

CALL Operation Steps:


Near CALL:
1. SP = SP - 2
2. [SS:SP] = IP (save current IP)  
3. IP = procedure address

Far CALL:
1. SP = SP - 2
2. [SS:SP] = CS (save current CS)
3. SP = SP - 2  
4. [SS:SP] = IP (save current IP)
5. CS:IP = procedure address

RET Instruction

RET instruction returns control to calling program by restoring address from stack.


RET             ; Near return
RET n           ; Near return with stack cleanup
RETF            ; Far return  
RETF n          ; Far return with stack cleanup

Near RET:
1. IP = [SS:SP] (restore IP)
2. SP = SP + 2

Far RET:
1. IP = [SS:SP] (restore IP)
2. SP = SP + 2
3. CS = [SS:SP] (restore CS)  
4. SP = SP + 2
Loading diagram...

Parameter Passing Techniques

1. Register Passing

Parameters passed through processor registers (fastest method).


; Main program
MOV AX, 10      ; First parameter
MOV BX, 20      ; Second parameter  
CALL ADD_PROC   ; Call procedure
; Result returned in AX

ADD_PROC PROC
    ADD AX, BX  ; Add parameters
    RET         ; Return result in AX
ADD_PROC ENDP

2. Stack Passing

Parameters passed through stack (allows unlimited parameters).


; Main program
PUSH 20         ; Second parameter (pushed first)
PUSH 10         ; First parameter (pushed second)
CALL ADD_PROC   ; Call procedure
ADD SP, 4       ; Clean up stack (2 parameters × 2 bytes)

ADD_PROC PROC
    PUSH BP     ; Save old BP
    MOV BP, SP  ; Set up stack frame
    
    MOV AX, [BP+4]  ; Get first parameter
    ADD AX, [BP+6]  ; Add second parameter
    
    POP BP      ; Restore BP
    RET         ; Return result in AX
ADD_PROC ENDP

3. Global Variable Passing

Parameters passed through memory locations.


PARAM1 DW ?     ; Global variables
PARAM2 DW ?
RESULT DW ?

; Main program
MOV PARAM1, 10
MOV PARAM2, 20
CALL ADD_PROC

ADD_PROC PROC
    MOV AX, PARAM1
    ADD AX, PARAM2
    MOV RESULT, AX
    RET
ADD_PROC ENDP

Stack Frames and Local Variables

Stack Frame Structure

A stack frame is created for each procedure call to manage local variables and parameters.

Loading diagram...

Stack Frame Example:


CALC_PROC PROC
    ; Procedure prologue
    PUSH BP         ; Save caller's BP
    MOV BP, SP      ; Set up new stack frame
    SUB SP, 6       ; Allocate 3 local variables (2 bytes each)
    
    ; Local variable access
    MOV WORD PTR [BP-2], 100   ; Local var 1
    MOV WORD PTR [BP-4], 200   ; Local var 2  
    MOV WORD PTR [BP-6], 300   ; Local var 3
    
    ; Parameter access
    MOV AX, [BP+4]  ; First parameter
    MOV BX, [BP+6]  ; Second parameter
    
    ; Procedure epilogue
    MOV SP, BP      ; Deallocate local variables
    POP BP          ; Restore caller's BP
    RET 4           ; Return and clean up 2 parameters
CALC_PROC ENDP

Stack Frame Memory Layout:


Memory Address    Content           Access Method
[BP+6]           Parameter 2        [BP+6]
[BP+4]           Parameter 1        [BP+4]  
[BP+2]           Return Address     (saved by CALL)
[BP+0]           Saved BP           [BP+0]
[BP-2]           Local Variable 1   [BP-2]
[BP-4]           Local Variable 2   [BP-4]
[BP-6]           Local Variable 3   [BP-6]

Recursive Procedures

Recursive procedures call themselves. Each recursive call creates a new stack frame.

Factorial Example:


; Calculate factorial recursively
; Input: AX = number, Output: AX = factorial

FACTORIAL PROC
    PUSH BP
    MOV BP, SP
    PUSH BX         ; Save registers
    
    CMP AX, 1       ; Check base case
    JLE BASE_CASE   ; If n <= 1, return 1
    
    ; Recursive case: n * factorial(n-1)
    MOV BX, AX      ; Save n
    DEC AX          ; n-1
    CALL FACTORIAL  ; Recursive call
    MUL BX          ; n * factorial(n-1)
    JMP DONE
    
BASE_CASE:
    MOV AX, 1       ; Return 1 for base case
    
DONE:
    POP BX          ; Restore registers
    POP BP
    RET
FACTORIAL ENDP

; Usage:
MOV AX, 5       ; Calculate 5!
CALL FACTORIAL  ; Result in AX = 120

Stack Growth in Recursion:


Call Stack for FACTORIAL(3):

Stack Frame 3: factorial(1) -> returns 1
Stack Frame 2: factorial(2) -> 2 * 1 = 2  
Stack Frame 1: factorial(3) -> 3 * 2 = 6
Main Program:  receives result 6

Stack-Based Calculations and Examples

Problem 1: Stack Space Calculation

Question: A program has 5 nested procedure calls, each using 4 local variables (2 bytes each). Calculate total stack space needed.

Solution:


Per procedure stack usage:
- Saved BP: 2 bytes
- Return address: 2 bytes (near call)  
- Local variables: 4 × 2 = 8 bytes
- Total per call: 2 + 2 + 8 = 12 bytes

For 5 nested calls:
Total stack space = 5 × 12 = 60 bytes

Additional considerations:
- Register saving: varies per procedure
- Parameters: depends on calling convention
- Temporary calculations: varies

Recommended stack size: 60 + 20% overhead = 72 bytes minimum

Problem 2: Parameter Passing Efficiency

Question: Compare clock cycles for register vs stack parameter passing for a procedure with 2 parameters.

Solution:


Register Passing:
MOV AX, param1    ; 4 cycles
MOV BX, param2    ; 4 cycles  
CALL proc         ; 19 cycles
Total: 27 cycles

Stack Passing:
PUSH param2       ; 15 cycles (memory to stack)
PUSH param1       ; 15 cycles
CALL proc         ; 19 cycles
ADD SP, 4         ; 4 cycles (cleanup)
Total: 53 cycles

Efficiency: Register passing is 53/27 = 1.96× faster
Time saved: (53-27)/53 = 49%

Answer: Register passing saves 49% execution time

Problem 3: Stack Overflow Detection

Question: Design a stack overflow check for a system with 1KB stack space.

Solution:


Given: Stack size = 1KB = 1024 bytes = 400H bytes

Stack organization:
Stack Base = SS:0FFFH (top of segment)
Stack Limit = SS:(0FFFH - 400H) = SS:0BFFH

Overflow check before PUSH:
CHECK_STACK PROC
    CMP SP, 0C00H   ; Check if SP near limit
    JA STACK_OK     ; Jump if SP > 0C00H (safe)
    
    ; Stack overflow error handling
    MOV AH, 09H     ; Display string function
    LEA DX, OVERFLOW_MSG
    INT 21H         ; DOS interrupt
    JMP EXIT_PROGRAM
    
STACK_OK:
    RET
CHECK_STACK ENDP

OVERFLOW_MSG DB 'Stack Overflow!$'

Usage before critical operations:
CALL CHECK_STACK
PUSH AX         ; Safe to push

Advanced Stack Techniques

1. Stack-Based Expression Evaluation

Use stack to evaluate complex expressions in postfix notation.


; Evaluate: 5 3 + 2 * (equals (5+3)*2 = 16)
PUSH 5          ; Stack: [5]
PUSH 3          ; Stack: [5, 3]
POP BX          ; BX = 3, Stack: [5]
POP AX          ; AX = 5, Stack: []
ADD AX, BX      ; AX = 8
PUSH AX         ; Stack: [8]
PUSH 2          ; Stack: [8, 2]  
POP BX          ; BX = 2, Stack: [8]
POP AX          ; AX = 8, Stack: []
MUL BX          ; AX = 16 (result)

2. Stack-Based Sorting Algorithm

Implement quicksort using stack for recursion simulation.


QUICKSORT PROC
    ; Simulate recursion using explicit stack
    PUSH 0          ; Start index
    PUSH array_size ; End index
    
SORT_LOOP:
    CMP SP, initial_SP  ; Check if stack empty
    JE DONE
    
    POP high        ; Get range to sort
    POP low
    
    ; Partition array and get pivot
    CALL PARTITION  ; Returns pivot in AX
    
    ; Push sub-ranges if needed
    CMP AX, low
    JLE SKIP_LEFT
    PUSH low
    PUSH AX
    DEC WORD PTR [SP]   ; AX-1
    
SKIP_LEFT:
    CMP AX, high  
    JGE SKIP_RIGHT
    PUSH AX
    INC WORD PTR [SP]   ; AX+1
    PUSH high
    
SKIP_RIGHT:
    JMP SORT_LOOP
    
DONE:
    RET
QUICKSORT ENDP

3. Exception Handling with Stack

Implement try-catch mechanism using stack frames.


; Exception handling structure
EXCEPTION_FRAME STRUC
    prev_frame    DW ?    ; Previous exception frame
    handler_addr  DW ?    ; Exception handler address
    saved_sp      DW ?    ; Stack pointer at try block
    saved_bp      DW ?    ; Base pointer at try block
EXCEPTION_FRAME ENDS

TRY_BLOCK PROC
    ; Set up exception frame
    SUB SP, SIZE EXCEPTION_FRAME
    MOV BP, SP
    
    MOV [BP].prev_frame, current_frame
    MOV [BP].handler_addr, OFFSET CATCH_BLOCK
    MOV [BP].saved_sp, SP
    MOV [BP].saved_bp, BP
    MOV current_frame, BP
    
    ; Protected code here
    CALL RISKY_OPERATION
    
    ; Normal cleanup
    CALL CLEANUP_EXCEPTION_FRAME
    RET
    
CATCH_BLOCK:
    ; Exception handler
    MOV SP, [BP].saved_sp
    MOV BP, [BP].saved_bp
    ; Handle exception...
    RET
TRY_BLOCK ENDP

Stack Performance Optimization

1. Minimize Stack Usage


; Inefficient: Multiple local variables
PROC1:
    PUSH BP
    MOV BP, SP
    SUB SP, 10      ; 5 local variables
    ; ... code ...
    MOV SP, BP
    POP BP
    RET

; Efficient: Reuse registers
PROC2:  
    PUSH BP
    PUSH AX         ; Save only needed registers
    PUSH BX
    ; Use AX, BX as "local variables"
    ; ... code ...
    POP BX
    POP AX
    POP BP
    RET

2. Optimize Parameter Passing


; For frequently called procedures with few parameters:
; Use registers instead of stack

; Inefficient
PUSH param1
PUSH param2  
CALL proc
ADD SP, 4

; Efficient
MOV AX, param1
MOV BX, param2
CALL proc

3. Stack Alignment

Align stack data for better performance on modern systems.


; Ensure stack is aligned to word boundaries
; This improves memory access performance

ALIGN_STACK PROC
    TEST SP, 1      ; Check if SP is odd
    JZ ALIGNED      ; Jump if even (aligned)
    DEC SP          ; Make SP even
ALIGNED:
    RET
ALIGN_STACK ENDP

Common Stack Programming Errors

1. Stack Imbalance


; Error: Unmatched PUSH/POP
PUSH AX
PUSH BX
POP AX      ; Error: Should POP BX first
; Stack now corrupted

; Correct:
PUSH AX
PUSH BX  
POP BX      ; Restore in reverse order
POP AX

2. Stack Overflow


; Error: Infinite recursion
ENDLESS_PROC:
    CALL ENDLESS_PROC   ; No base case!
    RET

; Correct: Include base case
FACTORIAL_PROC:
    CMP AX, 1
    JLE BASE_CASE       ; Base case prevents overflow
    DEC AX
    CALL FACTORIAL_PROC
    ; ... multiply logic ...
BASE_CASE:
    RET

3. Incorrect Stack Cleanup


; Error: Wrong parameter cleanup
PUSH param1
PUSH param2
CALL proc
ADD SP, 2       ; Error: Should be 4 for 2 parameters

; Correct:
PUSH param1  
PUSH param2
CALL proc
ADD SP, 4       ; Correct: 2 params × 2 bytes = 4

Summary

Stack operations and procedures are fundamental to 8086 programming. Proper understanding of stack mechanics, parameter passing, and procedure calls is essential for writing efficient and reliable assembly programs. Always maintain stack balance and consider performance implications when choosing parameter passing methods.

Key Points to Remember:

  • Stack grows downward (decreasing memory addresses)
  • PUSH decrements SP, POP increments SP
  • CALL saves return address, RET restores it
  • Use BP for stack frame management
  • Always balance PUSH/POP operations
  • Choose parameter passing method based on performance needs
  • Implement stack overflow protection in critical applications
  • Recursive procedures require careful stack management
Loading diagram...

Suggetested Articles