home *** CD-ROM | disk | FTP | other *** search
/ CD-X 1 / cdx_01.iso / demodisc / tyrant / docs / 386code / 16.386 < prev    next >
Encoding:
Text File  |  1994-01-20  |  20.1 KB  |  444 lines

  1. Chapter 16  Mixing 16-Bit and 32 Bit Code
  2.  
  3. ────────────────────────────────────────────────────────────────────────────
  4.  
  5. The 80386 running in protected mode is a 32-bit microprocessor, but it is
  6. designed to support 16-bit processing at three levels:
  7.  
  8.   1.  Executing 8086/80286 16-bit programs efficiently with complete 
  9.       compatibility.
  10.  
  11.   2.  Mixing 16-bit modules with 32-bit modules.
  12.  
  13.   3.  Mixing 16-bit and 32-bit addresses and operands within one module.
  14.  
  15. The first level of support for 16-bit programs has already been discussed
  16. in Chapter 13, Chapter 14, and Chapter 15. This chapter shows how 16-bit
  17. and 32-bit modules can cooperate with one another, and how one module can
  18. utilize both 16-bit and 32-bit operands and addressing.
  19.  
  20. The 80386 functions most efficiently when it is possible to distinguish
  21. between pure 16-bit modules and pure 32-bit modules. A pure 16-bit module
  22. has these characteristics:
  23.  
  24.   ■  All segments occupy 64 Kilobytes or less.
  25.   ■  Data items are either 8 bits or 16 bits wide.
  26.   ■  Pointers to code and data have 16-bit offsets.
  27.   ■  Control is transferred only among 16-bit segments.
  28.  
  29. A pure 32-bit module has these characteristics:
  30.  
  31.   ■  Segments may occupy more than 64 Kilobytes (zero bytes to 4 
  32.      gigabytes).
  33.  
  34.   ■  Data items are either 8 bits or 32 bits wide.
  35.  
  36.   ■  Pointers to code and data have 32-bit offsets.
  37.  
  38.   ■  Control is transferred only among 32-bit segments.
  39.  
  40. Pure 16-bit modules do exist; they are the modules designed for 16-bit
  41. microprocessors. Pure 32-bit modules may exist in new programs designed
  42. explicitly for the 80386. However, as systems designers move applications
  43. from 16-bit processors to the 32-bit 80386, it will not always be possible
  44. to maintain these ideals of pure 16-bit or 32-bit modules. It may be
  45. expedient to execute old 16-bit modules in a new 32-bit environment without
  46. making source-code changes to the old modules if any of the following
  47. conditions is true:
  48.  
  49.   ■  Modules will be converted one-by-one from 16-bit environments to
  50.      32-bit environments.
  51.  
  52.   ■  Older, 16-bit compilers and software-development tools will be
  53.      utilized in the new32-bit operating environment until new 32-bit
  54.      versions can be created.
  55.  
  56.   ■  The source code of 16-bit modules is not available for modification.
  57.  
  58.   ■  The specific data structures used by a given module inherently utilize
  59.      16-bit words.
  60.  
  61.   ■  The native word size of the source language is 16 bits.
  62.  
  63. On the 80386, 16-bit modules can be mixed with 32-bit modules. To design a
  64. system that mixes 16- and 32-bit code requires an understanding of the
  65. mechanisms that the 80386 uses to invoke and control its 32-bit and 16-bit
  66. features.
  67.  
  68.  
  69. 16.1  How the 80386 Implements 16-Bit and 32-Bit Features
  70.  
  71. The features of the architecture that permit the 80386 to work equally well
  72. with 32-bit and 16-bit address and operand sizes include:
  73.  
  74.   ■  The D-bit (default bit) of code-segment descriptors, which determines
  75.      the default choice of operand-size and address-size for the
  76.      instructions of a code segment. (In real-address mode and V86 mode,
  77.      which do not use descriptors, the default is 16 bits.) A code segment
  78.      whose D-bit is set is known as a USE32 segment; a code segment whose
  79.      D-bit is zero is a USE16 segment. The D-bit eliminates the need to
  80.      encode the operand size and address size in instructions when all
  81.      instructions use operands and effective addresses of the same size.
  82.  
  83.   ■  Instruction prefixes that explicitly override the default choice of
  84.      operand size and address size (available in protected mode as well as
  85.      in real-address mode and V86 mode).
  86.  
  87.   ■  Separate 32-bit and 16-bit gates for intersegment control transfers
  88.      (including call gates, interrupt gates, and trap gates). The operand
  89.      size for the control transfer is determined by the type of gate, not by
  90.      the D-bit or prefix of the transfer instruction.
  91.  
  92.   ■  Registers that can be used both for 32-bit and 16-bit operands and
  93.      effective-address calculations.
  94.  
  95.   ■  The B-bit (big bit) of data-segment descriptors, which determines the
  96.      size of stack pointer (32-bit ESP or 16-bit SP) used by the CPU for
  97.      implicit stack references.
  98.  
  99.  
  100. 16.2  Mixing 32-Bit and 16-Bit Operations
  101.  
  102. The 80386 has two instruction prefixes that allow mixing of 32-bit and
  103. 16-bit operations within one segment:
  104.  
  105.   ■  The operand-size prefix (66H)
  106.   ■  The address-size prefix (67H)
  107.  
  108. These prefixes reverse the default size selected by the D-bit. For example,
  109. the processor can interpret the word-move instruction MOV mem, reg in any of
  110. four ways:
  111.  
  112.   ■  In a USE32 segment:
  113.  
  114.      1.  Normally moves 32 bits from a 32-bit register to a 32-bit
  115.          effective address in memory.
  116.  
  117.      2.  If preceded by an operand-size prefix, moves 16 bits from a 16-bit
  118.          register to 32-bit effective address in memory.
  119.  
  120.      3.  If preceded by an address-size prefix, moves 32 bits from a 32-bit
  121.          register to a16-bit effective address in memory.
  122.  
  123.      4.  If preceded by both an address-size prefix and an operand-size
  124.          prefix, moves 16 bits from a 16-bit register to a 16-bit effective
  125.          address in memory.
  126.  
  127.   ■  In a USE16 segment:
  128.  
  129.      1.  Normally moves 16 bits from a 16-bit register to a 16-bit
  130.          effective address in memory.
  131.  
  132.      2.  If preceded by an operand-size prefix, moves 32 bits from a 32-bit
  133.          register to 16-bit effective address in memory.
  134.  
  135.      3.  If preceded by an address-size prefix, moves 16 bits from a 16-bit
  136.          register to a32-bit effective address in memory.
  137.  
  138.      4.  If preceded by both an address-size prefix and an operand-size
  139.          prefix, moves 32 bits from a 32-bit register to a 32-bit effective
  140.          address in memory.
  141.  
  142. These examples illustrate that any instruction can generate any combination
  143. of operand size and address size regardless of whether the instruction is in
  144. a USE16 or USE32 segment. The choice of the USE16 or USE32 attribute for a
  145. code segment is based upon these criteria:
  146.  
  147.   1.  The need to address instructions or data in segments that are larger
  148.       than 64 Kilobytes.
  149.  
  150.   2.  The predominant size of operands.
  151.  
  152.   3.  The addressing modes desired. (Refer to Chapter 17 for an explanation
  153.       of the additional addressing modes that are available when 32-bit
  154.       addressing is used.)
  155.  
  156. Choosing a setting of the D-bit that is contrary to the predominant size of
  157. operands requires the generation of an excessive number of operand-size
  158. prefixes.
  159.  
  160.  
  161. 16.3  Sharing Data Segments Among Mixed Code Segments
  162.  
  163. Because the choice of operand size and address size is defined in code
  164. segments and their descriptors, data segments can be shared freely among
  165. both USE16 and USE32 code segments. The only limitation is the one imposed
  166. by pointers with 16-bit offsets, which can only point to the first 64
  167. Kilobytes of a segment. When a data segment that contains more than 64
  168. Kilobytes is to be shared among USE32 and USE16 segments, the data that is
  169. to be accessed by the USE16 segments must be located within the first 64
  170. Kilobytes.
  171.  
  172. A stack that spans addresses less than 64K can be shared by both USE16 and
  173. USE32 code segments. This class of stacks includes:
  174.  
  175.   ■  Stacks in expand-up segments with G=0 and B=0.
  176.  
  177.   ■  Stacks in expand-down segments with G=0 and B=0.
  178.  
  179.   ■  Stacks in expand-up segments with G=1 and B=0, in which the stack is
  180.      contained completely within the lower 64 Kilobytes. (Offsets greater
  181.      than 64K can be used for data, other than the stack, that is not
  182.      shared.)
  183.  
  184. The B-bit of a stack segment cannot, in general, be used to change the size
  185. of stack used by a USE16 code segment. The size of stack pointer used by the
  186. processor for implicit stack references is controlled by the B-bit of the
  187. data-segment descriptor for the stack. Implicit references are those caused
  188. by interrupts, exceptions, and instructions such as PUSH, POP, CALL, and
  189. RET. One might be tempted, therefore, to try to increase beyond 64K the
  190. size of the stack used by 16-bit code simply by supplying a larger stack
  191. segment with the B-bit set. However, the B-bit does not control explicit
  192. stack references, such as accesses to parameters or local variables. A USE16
  193. code segment can utilize a "big" stack only if the code is modified so that
  194. all explicit references to the stack are preceded by the address-size
  195. prefix, causing those references to use 32-bit addressing.
  196.  
  197. In big, expand-down segments (B=1, G=1, and E=1), all offsets are greater
  198. than 64K, therefore USE16 code cannot utilize such a stack segment unless
  199. the code segment is modified to employ 32-bit addressing. (Refer to Chapter
  200. 6 for a review of the B, G, and E bits.)
  201.  
  202.  
  203. 16.4  Transferring Control Among Mixed Code Segments
  204.  
  205. When transferring control among procedures in USE16 and USE32 code
  206. segments, programmers must be aware of three points:
  207.  
  208.   ■  Addressing limitations imposed by pointers with 16-bit offsets.
  209.  
  210.   ■  Matching of operand-size attribute in effect for the CALL/RET pair and
  211.      theInterrupt/IRET pair so as to manage the stack correctly.
  212.  
  213.   ■  Translation of parameters, especially pointer parameters.
  214.  
  215. Clearly, 16-bit effective addresses cannot be used to address data or code
  216. located beyond 64K in a 32-bit segment, nor can large 32-bit parameters be
  217. squeezed into a 16-bit word; however, except for these obvious limits, most
  218. interfacing problems between 16-bit and 32-bit modules can be solved. Some
  219. solutions involve inserting interface procedures between the procedures in
  220. question.
  221.  
  222.  
  223. 16.4.1  Size of Code-Segment Pointer
  224.  
  225. For control-transfer instructions that use a pointer to identify the next
  226. instruction (i.e., those that do not use gates), the size of the offset
  227. portion of the pointer is determined by the operand-size attribute. The
  228. implications of the use of two different sizes of code-segment pointer are:
  229.  
  230.   ■  JMP, CALL, or RET from 32-bit segment to 16-bit segment is always
  231.      possible using a 32-bit operand size.
  232.  
  233.   ■  JMP, CALL, or RET from 16-bit segment using a 16-bit operand size
  234.      cannot address the target in a 32-bit segment if the address of the
  235.      target is greater than 64K.
  236.  
  237. An interface procedure can enable transfers from USE16 segments to 32-bit
  238. addresses beyond 64K without requiring modifications any more extensive than
  239. relinking or rebinding the old programs. The requirements for such an
  240. interface procedure are discussed later in this chapter.
  241.  
  242.  
  243. 16.4.2  Stack Management for Control Transfers
  244.  
  245. Because stack management is different for 16-bit CALL/RET than for 32-bit
  246. CALL/RET, the operand size of RET must match that of CALL. (Refer to Figure
  247. 16-1.) A 16-bit CALL pushes the 16-bit IP and (for calls between privilege
  248. levels) the 16-bit SP register. The corresponding RET must also use a 16-bit
  249. operand size to POP these 16-bit values from the stack into the 16-bit
  250. registers. A 32-bit CALL pushes the 32-bit EIP and (for interlevel calls)
  251. the 32-bit ESP register. The corresponding RET must also use a 32-bit
  252. operand size to POP these 32-bit values from the stack into the 32-bit
  253. registers. If the two halves of a CALL/RET pair do not have matching operand
  254. sizes, the stack will not be managed correctly and the values of the
  255. instruction pointer and stack pointer will not be restored to correct
  256. values.
  257.  
  258. When the CALL and its corresponding RET are in segments that have D-bits
  259. with the same values (i.e., both have 32-bit defaults or both have 16-bit
  260. defaults), there is no problem. When the CALL and its corresponding RET are
  261. in segments that have different D-bit values, however, programmers (or
  262. program development software) must ensure that the CALL and RET match.
  263.  
  264. There are three ways to cause a 16-bit procedure to execute a 32-bit call:
  265.  
  266.   1.  Use a 16-bit call to a 32-bit interface procedure that then uses a
  267.       32-bit call to invoke the intended target.
  268.  
  269.   2.  Bind the 16-bit call to a 32-bit call gate.
  270.  
  271.   3.  Modify the 16-bit procedure, inserting an operand-size prefix before
  272.       the call, thereby changing it to a 32-bit call.
  273.  
  274. Likewise, there are three ways to cause a 32-bit procedure to execute a
  275. 16-bit call:
  276.  
  277.   1.  Use a 32-bit call to a 32-bit interface procedure that then uses a
  278.       16-bit call to invoke the intended target.
  279.  
  280.   2.  Bind the 32-bit call to a 16-bit call gate.
  281.  
  282.   3.  Modify the 32-bit procedure, inserting an operand-size prefix before
  283.       the call, thereby changing it to a 16-bit call. (Be certain that the
  284.       return offset does not exceed 64K.)
  285.  
  286. Programmers can utilize any of the preceding methods to make a CALL in a
  287. USE16 segment match the corresponding RET in a USE32 segment, or to make a
  288. CALL in a USE32 segment match the corresponding RET in a USE16 segment.
  289.  
  290.  
  291. Figure 16-1.  Stack after Far 16-Bit and 32-Bit Calls
  292.  
  293.                            WITHOUT PRIVILEGE TRANSITION
  294.  
  295.                AFTER 16-BIT CALL                AFTER 32-BIT CALL
  296.  
  297.                31             0               31             0
  298.        D  O    ║               ║                ║               ║
  299.        I  F    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  300.        R       ║▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒║                ║▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒║
  301.        E  E    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  302.        C  X    ║ PARM2 │ PARM1 ║                ║     PARM2     ║
  303.        T  P    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  304.        I  A    ║  CS   │  IP   ║──SP           ║     PARM1     ║
  305.        O  N    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  306.        N  S    ║               ║                ║▒▒▒▒▒▒▒│  CS   ║
  307.           I    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  308.         │ O    ║               ║                ║      EIP      ║──ESP
  309.         │ N    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  310.         │      ║               ║                ║               ║
  311.                                                             
  312.  
  313.                            WITH PRIVILEGE TRANSITION
  314.  
  315.                AFTER 16-BIT CALL                AFTER 32-BIT CALL
  316.  
  317.        D  O     31            0                  31            0
  318.        I  F    ╔═══════╪═══════╗                ╔═══════╪═══════╗
  319.        R       ║   SS  │  SP   ║                ║▒▒▒▒▒▒▒│  SS   ║
  320.        E  E    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  321.        C  X    ║ PARM2 │ PARM1 ║                ║      ESP      ║
  322.        T  P    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  323.        I  A    ║  CS   │  IP   ║──SP           ║     PARM2     ║
  324.        O  N    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  325.        N  S    ║               ║                ║     PARM1     ║
  326.           I    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  327.         │ O    ║               ║                ║▒▒▒▒▒▒▒│  CS   ║
  328.         │ N    ╠═══════╪═══════╣                ╠═══════╪═══════╣
  329.         │      ║               ║                ║      EIP      ║──ESP
  330.               ╠═══════╪═══════╣                ╠═══════╪═══════╣
  331.                ║               ║                ║               ║
  332.                                                              
  333.  
  334.  
  335. 16.4.2.1  Controlling the Operand-Size for a Call
  336.  
  337. When the selector of the pointer referenced by a CALL instruction selects a
  338. segment descriptor, the operand-size attribute in effect for the CALL
  339. instruction is determined by the D-bit in the segment descriptor and by any
  340. operand-size instruction prefix.
  341.  
  342. When the selector of the pointer referenced by a CALL instruction selects a
  343. gate descriptor, the type of call is determined by the type of call gate. A
  344. call via an 80286 call gate (descriptor type 4)  always has a 16-bit
  345. operand-size attribute; a call via an 80386 call gate (descriptor type 12)
  346. always has a 32-bit operand-size attribute. The offset of the target
  347. procedure is taken from the gate descriptor; therefore, even a 16-bit
  348. procedure can call a procedure that is located more than 64 kilobytes from
  349. the base of a 32-bit segment, because a 32-bit call gate contains a 32-bit
  350. target offset.
  351.  
  352. An unmodified 16-bit code segment that has run successfully on an 8086 or
  353. real-mode 80286 will always have a D-bit of zero and will not use
  354. operand-size override prefixes; therefore, it will always execute 16-bit
  355. versions of CALL. The only modification needed to make a16-bit procedure
  356. effect a 32-bit call is to relink the call to an 80386 call gate.
  357.  
  358.  
  359. 16.4.2.2  Changing Size of Call
  360.  
  361. When adding 32-bit gates to 16-bit procedures, it is important to consider
  362. the number of parameters. The count field of the gate descriptor specifies
  363. the size of the parameter string to copy from the current stack to the stack
  364. of the more privileged procedure. The count field of a 16-bit gate specifies
  365. the number of words to be copied, whereas the count field of a 32-bit gate
  366. specifies the number of doublewords to be copied; therefore, the 16-bit
  367. procedure must use an even number of words as parameters.
  368.  
  369.  
  370. 16.4.3  Interrupt Control Transfers
  371.  
  372. With a control transfer due to an interrupt or exception, a gate is always
  373. involved. The operand-size attribute for the interrupt is determined by the
  374. type of IDT gate.
  375.  
  376. A 386 interrupt or trap gate (descriptor type 14 or 15) to a 32-bit
  377. interrupt procedure can be used to interrupt either 32-bit or 16-bit
  378. procedures. However, it is not generally feasible to permit an interrupt or
  379. exception to invoke a 16-bit handler procedure when 32-bit code is
  380. executing, because a 16-bit interrupt procedure has a return offset of only
  381. 16-bits on its stack. If the 32-bit procedure is executing at an address
  382. greater than 64K, the 16-bit interrupt procedure cannot return correctly.
  383.  
  384.  
  385. 16.4.4  Parameter Translation
  386.  
  387. When segment offsets or pointers (which contain segment offsets) are passed
  388. as parameters between 16-bit and 32-bit procedures, some translation is
  389. required. Clearly, if a 32-bit procedure passes a pointer to data located
  390. beyond 64K to a 16-bit procedure, the 16-bit procedure cannot utilize it.
  391. Beyond this natural limitation, an interface procedure can perform any
  392. format conversion between 32-bit and 16-bit pointers that may be needed.
  393.  
  394. Parameters passed by value between 32-bit and 16-bit code may also require
  395. translation between 32-bit and 16-bit formats. Such translation requirements
  396. are application dependent. Systems designers should take care to limit the
  397. range of values passed so that such translations are possible.
  398.  
  399.  
  400. 16.4.5  The Interface Procedure
  401.  
  402. Interposing an interface procedure between 32-bit and 16-bit procedures can
  403. be the solution to any of several interface requirements:
  404.  
  405.   ■  Allowing procedures in 16-bit segments to transfer control to
  406.      instructions located beyond 64K in 32-bit segments.
  407.  
  408.   ■  Matching of operand size for CALL/RET.
  409.  
  410.   ■  Parameter translation.
  411.  
  412. Interface procedures between USE32 and USE16 segments can be constructed
  413. with these properties:
  414.  
  415.   ■  The procedures reside in a code segment whose D-bit is set, indicating
  416.      a default operand size of 32-bits.
  417.  
  418.   ■  All entry points that may be called by 16-bit procedures have offsets
  419.      that are actually less than 64K.
  420.  
  421.   ■  All points to which called 16-bit procedures may return also lie
  422.      within 64K.
  423.  
  424. The interface procedures do little more than call corresponding procedures
  425. in other segments. There may be two kinds of procedures:
  426.  
  427.   ■  Those that are called by 16-bit procedures and call 32-bit procedures.
  428.      These interface procedures are called by 16-bit CALLs and use the
  429.      operand-size prefix before RET instructions to cause a 16-bit RET.
  430.      CALLs to 32-bit segments are 32-bit calls (by default, because the
  431.      D-bit is set), and the 32-bit code returns with 32-bit RET
  432.      instructions.
  433.  
  434.   ■  Those that are called by 32-bit procedures and call 16-bit procedures.
  435.      These interface procedures are called by 32-bit CALL instructions, and
  436.      return with 32-bit RET instructions (by default, because the D-bit is
  437.      set).  CALLs to 16-bit procedures use the operand-size prefix;
  438.      procedures in the 16-bit code return with 16-bit RET instructions.
  439.  
  440.  
  441.                          PART IV  INSTRUCTION SET                          
  442.  
  443.  
  444.