Vol. 3 18-7
MIXING 16-BIT AND 32-BIT CODE
While executing 32-bit code, if a call is made to a 16-bit code segment which is at the
same or a more privileged level (that is, the DPL of the called code segment is less
than or equal to the CPL of the calling code segment) through a 16-bit call gate, then
the upper 16-bits of the ESP register may be unreliable upon returning to the 32-bit
code segment (that is, after executing a RET in the 16-bit code segment).
When the CALL instruction and its matching RET instruction are in code segments
that have D flags with the same values (that is, both are 32-bit code segments or
both are 16-bit code segments), the default settings may be used. When the CALL
instruction and its matching RET instruction are in segments which have different
D-flag settings, an operand-size prefix must be used.
18.4.2.1 Controlling the Operand-Size Attribute For a Call
Three things can determine the operand-size of a call:
• The D flag in the segment descriptor for the calling code segment.
• An operand-size instruction prefix.
• The type of call gate (16-bit or 32-bit), if a call is made through a call gate.
When a call is made with a pointer (rather than a call gate), the D flag for the calling
code segment determines the operand-size for the CALL instruction. This operand-
size attribute can be overridden by prepending an operand-size prefix to the CALL
instruction. So, for example, if the D flag for a code segment is set for 16 bits and the
operand-size prefix is used with a CALL instruction, the processor will cause the infor
-
mation stored on the stack to be stored in 32-bit format. If the call is to a 32-bit code
segment, the instructions in that code segment will be able to read the stack coher-
ently. Also, a RET instruction from the 32-bit code segment without an operand-size
prefix will maintain stack coherency with the 16-bit code segment being returned to.
When a CALL instruction references a call-gate descriptor, the type of call is deter-
mined by the type of call gate (16-bit or 32-bit). The offset to the destination in the
code segment being called is taken from the gate descriptor; therefore, if a 32-bit call
gate is used, a procedure in a 16-bit code segment can call a procedure located more
than 64 KBytes from the base of a 32-bit code segment, because a 32-bit call gate
uses a 32-bit offset.
Note that regardless of the operand size of the call and how it is determined, the size
of the stack pointer used (SP or ESP) is always controlled by the B flag in the stack-
segment descriptor currently in use (that is, when B is clear, SP is used, and when B
is set, ESP is used).
An unmodified 16-bit code segment that has run successfully on an 8086 processor
or in real-mode on a later IA-32 architecture processor will have its D flag clear and
will not use operand-size override prefixes. As a result, all CALL instructions in this
code segment will use the 16-bit operand-size attribute. Procedures in these code