7.4 Stack, Procedures, and Parameters
Section 7.3 showed that memory gains structure through a shared layout contract. A procedure call uses the stack in exactly this way. The processor automatically pushes a return address, while caller and callee agree where parameters, saved registers, and local storage will appear.
CALL and RET create a return path
A procedure is a reusable instruction sequence with a defined entry and return. A near CALL target performs two linked actions:
1. Push the offset of the instruction after CALL as the return IP.
2. Load IP with the target offset.
A near RET pops that saved offset into IP. The push and pop must refer to the same active stack layout; otherwise RET transfers control to a word that was never intended as an instruction address.
A far call also saves CS because it crosses code segments. This section uses near calls so one return word is enough. The same accounting principle extends to far calls with a larger return address.
BP gives a stable base while SP moves
A stack frame is the active region holding one procedure invocation's saved state, return information, parameters, and local variables. SP identifies the current top and changes whenever data is pushed or local space is reserved. BP can be copied from SP and kept stable, so each field has a fixed BP-relative offset.
Assume the caller pushes one word parameter and makes a near call:
PUSH 0005H
CALL double_word
ADD SP,2 ; caller removes its parameterThe procedure establishes and removes a frame:
double_word PROC NEAR
PUSH BP
MOV BP,SP
SUB SP,2 ; one local word at [BP-2]
MOV AX,[BP+4] ; parameter
SHL AX,1
MOV [BP-2],AX
MOV SP,BP
POP BP
RET
double_word ENDPWith initial SP=0100H, the parameter is pushed at 00FEH, CALL puts return IP at 00FCH, and PUSH BP puts old BP at 00FAH. After MOV BP,SP and SUB SP,2, BP remains 00FAH while SP becomes 00F8H. The parameter is therefore [BP+4] even while SP changes.
MOV SP,BP releases all locals at once. POP BP restores the caller's frame base. RET consumes the return IP, and the caller's ADD SP,2 removes its parameter. Final SP must equal its pre-call value.
A calling convention is a shared contract
A calling convention states how independently written caller and callee cooperate. Even a small course program needs answers to these questions:
- Where are parameters placed: registers, stack, memory, or a mixture?
- Where is the return value placed?
- Which registers may the callee overwrite, and which must it restore?
- Who removes stack parameters?
- In what order are multiword parameters stored?
There is no single universal 8086 convention. A project may choose one, but every call site and procedure must use the same choice.
For a caller-cleanup stack convention, a callee that must preserve BX can use:
twice PROC NEAR
PUSH BP
MOV BP,SP
PUSH BX
MOV BX,[BP+4]
MOV AX,BX
SHL AX,1
POP BX
POP BP
RET
twice ENDPThe caller later executes ADD SP,2. If the callee instead uses RET 2, the immediate 2 tells RET to discard one additional parameter word after popping the return address. That is callee cleanup. Using RET 2 and caller ADD SP,2 together removes the same parameter twice and leaves SP two bytes above its original value.
A caller-saved register may be overwritten by the callee, so the caller preserves it when needed. A callee-saved register must have the same value on return, so the procedure saves and restores it. The contract—not the register's name—decides ownership.
Nested calls strengthen the test. If twice calls a helper, a new return address is pushed inside the current frame. Saved registers and parameters must remain reachable, and every exit path must restore the same SP and saved values. A correct AX result alone does not prove the call was safe.
Procedures provide runtime reuse with explicit stack and register costs. Section 7.5 compares them with source-level macro expansion, then extends program organization across separately assembled modules.