HALICERY

free-time coding, hardware dev, articles

Top
Home 8042 Blogs About
Home IntelEssential 16/32-bit Instructions CALL

Last modified: Tue Jun 30 09:56:03 UTC+0200 2026 © A. Tarpai


CALL and RET

8086 CALL and RET

Before the jump, the current program position is pushed on stack. Either IP (near CALL) or both CS and IP (far CALL). These are different opcodes. A matching near/far RET pops the return address. Both have optional N-bytes "pop".

Far call stack, HW/SW interrupt stack: both CS and IP is pushed onto the stack. SP points to similar structure as memory indirect storage: IP (low) then CS (high).

IRET is far and also pops the flags.

   near stack                       far stack                        INT stack

15             0                 15             0                 15             0
|              |                 |              |                 |              |
+--------------+                 +--------------+                 +--------------+
|  X  X  X  X  |                 |  X  X  X  X  |                 |  X  X  X  X  |
+--------------+                 +--------------+                 +--------------+
|  X  X  X  X  | <-- SP+2        |  X  X  X  X  | <-- SP+4        |  X  X  X  X  | <-- SP+6
+--------------+                 +--------------+                 +--------------+
|      IP      | <-- SP          |      CS      |                 |     FLAGS    |
+--------------+                 +--------------+                 +--------------+
|              |                 |      IP      | <-- SP          |      CS      |
+--------------+                 +--------------+                 +--------------+
|              |                 |              |                 |      IP      | <-- SP
+--------------+                 +--------------+                 +--------------+
|              |                 |              |                 |              |
+--------------+                 +--------------+                 +--------------+
|              |                 |              |                 |              |
+--------------+ 0               +--------------+ 0               +--------------+ 0


   C3  RET                          CB  RETF                         CF  IRET




E8 EC FF   call  -20           9A 7856 3412   call 1234h:5678h       HW/SW INT
FF 50 02   call [bx+si+2]      FF 58 02       call far [bx+si+2]
FF D0      call ax
     ...                              ...                              ...
     ...                              ...                              ...
     ...                              ...                              ...

C3        RET                  CB        RETF                        CF  IRET
C2 LO HI  RET n                CA LO HI  RETF n

RET N and RETF N

A 16-bit word operand follows opcode (N):

RET N    C2 imm16
RETF N   CA imm16

Add N to SP after the return address is popped, i.e. to clean passed parameters (the callee cleans the stack). The addition is unsigned.

Example:

Caller pushed 3 WORD parameters and executed near/far CALL

N is 3 x 2 = 6


   near stack                                  far stack

15             0                           15             0
|              |                           |              |
+--------------+                           +--------------+
|  X  X  X  X  | <-- SP before             |  X  X  X  X  | <-- SP before
+--------------+                           +--------------+
|    param 3   |                           |    param 3   |
+--------------+                           +--------------+
|    param 2   |                           |    param 2   |
+--------------+                           +--------------+
|    param 1   | <-- SP + 2                |    param 1   | <-- SP + 4
+--------------+                           +--------------+
|      IP      | <-- SP                    |      CS      |
+--------------+                           +--------------+
|              |                           |      IP      | <-- SP
                                           +--------------+
                                           |              |

C2 06 00  RET 6                            CA 06 00  RETF 6

1. pop word into IP                        1. pop word into IP
2. increment SP by two                     2. increment SP by two
3. add N to SP                             3. pop word into CS
4. stack restored by callee                4. increment SP by two
                                           3. add N to SP
                                           4. stack restored by callee

Note. This is not how the C language compiler works, there the caller cleans up the stack, with eg. ADD SP, 8 – as the caller knows exactly how many parameters were pushed. RET N is what MS calls __stdcall.

386 CALL and RET

Operand-size attribute (either implicit from D-bit or overridden by 66h prefix) determines

Another issue here is the B-bit: but see push.

When operand-size = 16:

               operand-size = 16             operand-size = 32
               D=0 or D=1 and 66h            D=1 or D=0 and 66h


                      push cs word              push cs dword
                      +---------+           +---------+---------+
FAR CALL              |    CS   |           | .......     CS    |
                      +---------+           +---------+---------+

                      push ip word             push eip dword
                      +---------+           +-------------------+
CALL                  |    IP   |           |        EIP        |
                      +---------+           +-------------------+
                           |                          |
                        LOAD IP                    LOAD EIP
                           |                          |
                           v                          v
            +---------+---------+           +-------------------+
            |000000000|         | EIP       |                   | EIP
            +---------+---------+           +-------------------+
                           ^                          ^
                           |                          |
                        LOAD IP                    LOAD EIP
                           |                          |
                      +---------+           +-------------------+
RET                   |    IP   |           |        EIP        |
                      +---------+           +-------------------+
                      pop ip word                pop eip dword

                      +---------+           +---------+---------+
RETF                  |    CS   |           | xxxxxxx     CS    |
                      +---------+           +---------+---------+
                      pop cs word               pop cs dword


(.) padded with high-order bits, zeroed or word move and HI on stack unchanged (CPU-variations)
(x) high-order 16-bits discarded

386 RET N

Unchanged opcodes in 32-bit:

  1. N is still number of bytes
  2. N is still a 16-bit unsigned value

Eg. to pop 3 DWORD parameters N = 12.

             operand-size = 16               operand-size = 32
             D=0 or D=1 and 66h              D=1 or D=0 and 66h


                      +---------+           +---------+---------+
                      |  imm16  |           | 0 0 0 0    imm16  |
                      +---------+           +---------+---------+

            +---------+---------+           +-------------------+
            | . . . . |    SP   | ESP       |                   | ESP
            +---------+---------+           +-------------------+

             SP = SP + imm16                  ESP = ESP + imm16

            (.) ESP HI unchanged              imm16 zero-extended
                                              unsigned addition