Intel and compatable CPU's Programming Information
prev: 16.3 Sharing Data Segments Among Mixed Code Segments
next: Chapter 17 -- 80386 Instruction Set
16.4 Transferring Control Among Mixed Code SegmentsWhen transferring control among procedures in USE16 and USE32 code segments, programmers must be aware of three points:
16.4.1 Size of Code-Segment PointerFor control-transfer instructions that use a pointer to identify the next instruction (i.e., those that do not use gates), the size of the offset portion of the pointer is determined by the operand-size attribute. The implications of the use of two different sizes of code-segment pointer are:
16.4.2 Stack Management for Control TransfersBecause stack management is different for 16-bit CALL/RET than for 32-bit CALL/RET, the operand size of RET must match that of CALL. (Refer to Figure 16-1 .) A 16-bit CALL pushes the 16-bit IP and (for calls between privilege levels) the 16-bit SP register. The corresponding RET must also use a 16-bit operand size to POP these 16-bit values from the stack into the 16-bit registers. A 32-bit CALL pushes the 32-bit EIP and (for interlevel calls) the 32-bit ESP register. The corresponding RET must also use a 32-bit operand size to POP these 32-bit values from the stack into the 32-bit registers. If the two halves of a CALL/RET pair do not have matching operand sizes, the stack will not be managed correctly and the values of the instruction pointer and stack pointer will not be restored to correct values.
When the CALL and its corresponding RET are in segments that have D-bits with the same values (i.e., both have 32-bit defaults or both have 16-bit defaults), there is no problem. When the CALL and its corresponding RET are in segments that have different D-bit values, however, programmers (or program development software) must ensure that the CALL and RET match.
There are three ways to cause a 16-bit procedure to execute a 32-bit call:
When the selector of the pointer referenced by a CALL instruction selects a gate descriptor, the type of call is determined by the type of call gate. A call via an 80286 call gate (descriptor type 4) always has a 16-bit operand-size attribute; a call via an 80386 call gate (descriptor type 12) always has a 32-bit operand-size attribute. The offset of the target procedure is taken from the gate descriptor; therefore, even a 16-bit procedure can call a procedure that is located more than 64 kilobytes from the base of a 32-bit segment, because a 32-bit call gate contains a 32-bit target offset.
An unmodified 16-bit code segment that has run successfully on an 8086 or real-mode 80286 will always have a D-bit of zero and will not use operand-size override prefixes; therefore, it will always execute 16-bit versions of CALL. The only modification needed to make a16-bit procedure effect a 32-bit call is to relink the call to an 80386 call gate.
126.96.36.199 Changing Size of CallWhen adding 32-bit gates to 16-bit procedures, it is important to consider the number of parameters. The count field of the gate descriptor specifies the size of the parameter string to copy from the current stack to the stack of the more privileged procedure. The count field of a 16-bit gate specifies the number of words to be copied, whereas the count field of a 32-bit gate specifies the number of doublewords to be copied; therefore, the 16-bit procedure must use an even number of words as parameters.
16.4.3 Interrupt Control TransfersWith a control transfer due to an interrupt or exception, a gate is always involved. The operand-size attribute for the interrupt is determined by the type of IDT gate.
A 386 interrupt or trap gate (descriptor type 14 or 15) to a 32-bit interrupt procedure can be used to interrupt either 32-bit or 16-bit procedures. However, it is not generally feasible to permit an interrupt or exception to invoke a 16-bit handler procedure when 32-bit code is executing, because a 16-bit interrupt procedure has a return offset of only 16-bits on its stack. If the 32-bit procedure is executing at an address greater than 64K, the 16-bit interrupt procedure cannot return correctly.
16.4.4 Parameter TranslationWhen segment offsets or pointers (which contain segment offsets) are passed as parameters between 16-bit and 32-bit procedures, some translation is required. Clearly, if a 32-bit procedure passes a pointer to data located beyond 64K to a 16-bit procedure, the 16-bit procedure cannot utilize it. Beyond this natural limitation, an interface procedure can perform any format conversion between 32-bit and 16-bit pointers that may be needed.
Parameters passed by value between 32-bit and 16-bit code may also require translation between 32-bit and 16-bit formats. Such translation requirements are application dependent. Systems designers should take care to limit the range of values passed so that such translations are possible.
16.4.5 The Interface ProcedureInterposing an interface procedure between 32-bit and 16-bit procedures can be the solution to any of several interface requirements: