en:docs:win16:thunking

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:docs:win16:thunking [2026/06/03 07:49] prokusheven:docs:win16:thunking [2026/06/03 08:41] (current) – [The Old New Thing (Raymond Chen)] prokushev
Line 41: Line 41:
 This document describes all these thunk variants in technical detail, from the early real‑mode thunks to the last 16‑32 bridges used in Windows 9x and NT. This document describes all these thunk variants in technical detail, from the early real‑mode thunks to the last 16‑32 bridges used in Windows 9x and NT.
  
-====== 1. Instance Thunk (Win16) ======+===== 1. Instance Thunk (Win16) =====
  
-=== 1.1 Architectural root of the problem: shared code, private data ===+==== 1.1 Architectural root of the problem: shared code, private data ====
  
 In 16‑bit Windows, multiple instances of the same application share code but each instance has its own **data segment (DS)**. When Windows calls a callback function (window procedure, ''EnumFonts'', ''SetTimer'', etc.), the system does not know which DS to use for that particular instance. The 8086 processor had no MMU; all memory was physical, with no indirection layer. This meant that if the memory manager moved a data segment, it had to know about every reference to it in order to update pointers. This situation gave rise to a special mechanism – the **Instance Thunk**. In 16‑bit Windows, multiple instances of the same application share code but each instance has its own **data segment (DS)**. When Windows calls a callback function (window procedure, ''EnumFonts'', ''SetTimer'', etc.), the system does not know which DS to use for that particular instance. The 8086 processor had no MMU; all memory was physical, with no indirection layer. This meant that if the memory manager moved a data segment, it had to know about every reference to it in order to update pointers. This situation gave rise to a special mechanism – the **Instance Thunk**.
  
-=== 1.2 Role of the loader and the NE format ===+==== 1.2 Role of the loader and the NE format ====
  
 The foundation of the mechanism is laid when the executable file is loaded. Windows 3.x uses the **NE (New Executable)** format, in which each far (''FAR'') function has a 6‑byte record in the Entry Table. This table is placed by the loader in a fixed overhead segment that is shared by all instances of the program. The foundation of the mechanism is laid when the executable file is loaded. Windows 3.x uses the **NE (New Executable)** format, in which each far (''FAR'') function has a 6‑byte record in the Entry Table. This table is placed by the loader in a fixed overhead segment that is shared by all instances of the program.
Line 53: Line 53:
 During loading, Windows **expands each 6‑byte entry table record into an 8‑byte fragment of machine code** called a **reload thunk**. These thunks become the official, single entry point for calling any corresponding far function. During loading, Windows **expands each 6‑byte entry table record into an 8‑byte fragment of machine code** called a **reload thunk**. These thunks become the official, single entry point for calling any corresponding far function.
  
-=== 1.3 Reload thunk: detailed structure and swapping mechanism ===+==== 1.3 Reload thunk: detailed structure and swapping mechanism ====
  
 **Full reload thunk structure (8 bytes):** **Full reload thunk structure (8 bytes):**
Line 92: Line 92:
 5. **Discarding** – when the system needs memory, the kernel may discard the code segment. Upon discarding, the reload thunk is restored to its original state (''INT 3Fh'' with operands) using saved data in the segment table. 5. **Discarding** – when the system needs memory, the kernel may discard the code segment. Upon discarding, the reload thunk is restored to its original state (''INT 3Fh'' with operands) using saved data in the segment table.
  
-=== 1.4 Three prolog types for exported functions ===+==== 1.4 Three prolog types for exported functions ====
  
 The loader not only creates reload thunks, but also **modifies the prolog of exported functions**, replacing the first 2‑3 bytes with ''NOP'' instructions. There are three prolog types: The loader not only creates reload thunks, but also **modifies the prolog of exported functions**, replacing the first 2‑3 bytes with ''NOP'' instructions. There are three prolog types:
Line 128: Line 128:
   </code>   </code>
  
-=== 1.5 MakeProcInstance: dynamic binding to an instance ===+==== 1.5 MakeProcInstance: dynamic binding to an instance ====
  
 ''MakeProcInstance'' creates a thunk that binds a function call to a specific instance's data. It dynamically generates an 8‑byte code fragment in a fixed memory area: ''MakeProcInstance'' creates a thunk that binds a function call to a specific instance's data. It dynamically generates an 8‑byte code fragment in a fixed memory area:
Line 150: Line 150:
 6. The function body executes. 6. The function body executes.
  
-=== 1.6 CallProcInstance and the return thunk ===+==== 1.6 CallProcInstance and the return thunk ====
  
 ''CallProcInstance'' is an **undocumented kernel function** that, together with a special **return thunk** mechanism, solves the problem of returning into a discarded code segment. Prototype: ''CallProcInstance'' is an **undocumented kernel function** that, together with a special **return thunk** mechanism, solves the problem of returning into a discarded code segment. Prototype:
Line 168: Line 168:
 - This idempotency was provided by ''CallProcInstance''. - This idempotency was provided by ''CallProcInstance''.
  
-=== 1.7 Evolution and redundancy of MakeProcInstance ===+==== 1.7 Evolution and redundancy of MakeProcInstance ====
  
 Later it was discovered that ''MakeProcInstance'' was often unnecessary. Later it was discovered that ''MakeProcInstance'' was often unnecessary.
Line 179: Line 179:
 In modern 32‑bit and 64‑bit Windows, ''MakeProcInstance'' is a stub macro that simply returns the passed pointer, and ''FreeProcInstance'' does nothing. In modern 32‑bit and 64‑bit Windows, ''MakeProcInstance'' is a stub macro that simply returns the passed pointer, and ''FreeProcInstance'' does nothing.
  
-=== 1.8 Complete call flow summary ===+==== 1.8 Complete call flow summary ====
  
 1. **Loading** – the loader reconstructs the Entry Table into reload thunks (''SAR'', ''INT 3Fh'', ''entry_segment'', ''entry_offset'') and modifies the prologs of exported functions (replacing the beginning with ''NOP''s). 1. **Loading** – the loader reconstructs the Entry Table into reload thunks (''SAR'', ''INT 3Fh'', ''entry_segment'', ''entry_offset'') and modifies the prologs of exported functions (replacing the beginning with ''NOP''s).
Line 191: Line 191:
 9. **Return** – if the code segment was discarded while the function was running, the return thunk mechanism (part of ''CallProcInstance'') reloads the segment and transfers control to the saved return address. 9. **Return** – if the code segment was discarded while the function was running, the return thunk mechanism (part of ''CallProcInstance'') reloads the segment and transfers control to the saved return address.
  
-=== 1.9 API and ordinals ===+==== 1.9 API and ordinals ====
  
 ^ Function ^ Export ^ Ordinal (KERNEL.EXE 3.10) ^ ^ Function ^ Export ^ Ordinal (KERNEL.EXE 3.10) ^
Line 218: Line 218:
 | **517** | ''CallProc32W'' | Calls a 32-bit function with parameter conversion (Pascal calling convention). | | **517** | ''CallProc32W'' | Calls a 32-bit function with parameter conversion (Pascal calling convention). |
  
-Later ''CallProcEx32W'' appeared (no fixed ordinal), supporting ''__cdecl'' and the flag ''CPEX_DEST_CDECL''.+Later CallProcEx32W appeared (no fixed ordinal), supporting cdecl and the flag ''CPEX_DEST_CDECL''.
  
 ==== 2.3 API functions: prototypes and parameters ==== ==== 2.3 API functions: prototypes and parameters ====
Line 706: Line 706:
 ===== References ===== ===== References =====
  
-* Finnegan, J. "Test Drive Win32 from 16-bit Code Using the Windows NT WOW Layer and Generic Thunk". Microsoft Systems Journal, June 1994. (PDF: ''24.pdf''+  * Finnegan, J. "Test Drive Win32 from 16-bit Code Using the Windows NT WOW Layer and Generic Thunk". Microsoft Systems Journal, June 1994. (PDF: ''24.pdf''
-* Oney, W. "Mix 16-bit and 32-bit Code in Your Applications with the Win32s Universal Thunk". Microsoft Systems Journal, November 1993. (PDF: ''mix16.pdf''+  * Oney, W. "Mix 16-bit and 32-bit Code in Your Applications with the Win32s Universal Thunk". Microsoft Systems Journal, November 1993. (PDF: ''mix16.pdf''
-* Pietrek, M. "Windows 95 System Programming Secrets". IDG Books, 1996. (Chapter on ''QT_Thunk''+  * Pietrek, M. "Windows 95 System Programming Secrets". IDG Books, 1996. (Chapter on ''QT_Thunk''
-* Petzold, C. "Programming Windows 3.1". Microsoft Press, 1992. (Chapters on ''MakeProcInstance''+  * Petzold, C. "Programming Windows 3.1". Microsoft Press, 1992. (Chapters on ''MakeProcInstance''
-* Wine source code: ''dlls/wow32/thunk.c'', ''include/wine/thunk.h'' +  * Wine source code: ''dlls/wow32/thunk.c'', ''include/wine/thunk.h'' 
-* Microsoft Win32 SDK for Windows NT 3.5, files: ''WOWNT16.H'', ''WOWNT32.H'' +  * Microsoft Win32 SDK for Windows NT 3.5, files: ''WOWNT16.H'', ''WOWNT32.H'' 
-* Microsoft Knowledge Base article Q104009: "Generic Thunk Interface in Windows NT"+  * Microsoft Knowledge Base article Q104009: "Generic Thunk Interface in Windows NT" 
 + 
 + 
 +===== References ===== 
 + 
 +==== Official Microsoft documentation (MSDN / KB) ==== 
 + 
 +  * [[https://library.thedatadungeon.com/msdn-1992-09/progwin/html/prog5ip4.content.htm|When Windows Runs the Program (MSDN 1992)]] – describes reload thunk structure, ''SAR'', ''INT 3Fh'', and the two states. 
 +  * [[https://library.thedatadungeon.com/msdn-1992-09/progwin/html/prog5iqw.content.htm|What MakeProcInstance Does (MSDN 1992)]] – official description of instance thunk creation. 
 +  * [[https://jeffpar.github.io/kbarchive/kb/105/Q105137/|Q105137: Explanation of Exporting Functions in Windows]] – details the three prolog types. 
 +  * [[https://betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/102871|Microsoft KB Archive/102871]] – compiler switches ''-GA -GEa'' required for callbacks. 
 +  * [[https://betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/81496|Microsoft KB Archive/81496]] – clarifies ''HINSTANCE'' vs ''HMODULE''
 + 
 +==== The Old New Thing (Raymond Chen) ==== 
 + 
 +  * [[https://devblogs.microsoft.com/oldnewthing/20080207-00/?p=23533|What did MakeProcInstance do? (February 7, 2008)]] – explanation of the mechanism, its necessity due to lack of MMU, and why it became redundant. 
 +  * [[https://devblogs.microsoft.com/oldnewthing/20180423-00/?p=98575|The early history of redundant function pointer casts: MakeProcInstance (April 23, 2018)]] – concludes that ''MakeProcInstance'' is now a stub. 
 +  * [[https://devblogs.microsoft.com/oldnewthing/20080208-00/?p=23513|Why couldn't you have more than one instance of a 16-bit multi-DS program? (February 8, 2008)]] - explanation of the DS segment usage 
 + 
 +==== Historical analysis and discoveries ==== 
 + 
 +  * [[http://www.geary.com/fixds.html|FixDS – a bit of Windows history (Michael Geary)]] – first-hand account of how ''MakeProcInstance'' was eliminated for EXEs using ''__export'' and for DLLs using ''__loadds''
 + 
 +==== Reverse engineering (Wine and WineVDM) ==== 
 + 
 +  * [[https://source.winehq.org/git/wine.git/blob/HEAD:/dlls/wow32/thunk.c|Wine thunk.c]] – source code showing ''TASK_AllocThunk'' and how instance thunks are allocated. 
 +  * [[https://deepwiki.com/otya128/winevdm/Task_Management|WineVDM Task Management]] – explains per‑task thunk management. 
 + 
 +==== General reference and third‑party ==== 
 + 
 +  * [[https://www.gladir.com/CODER/CWINDOWS3/callprocinstance.htm|CallProcInstance (gladir.com)]] – documented syntax of the undocumented ''CallProcInstance''
 +  * [[https://wiki.osdev.org/NE|NE (New Executable) Format (OSDev Wiki)]] – technical specification of the NE format and the Entry Table. 
 +  * [[https://en.wikipedia.org/wiki/Thunk|Thunk – Wikipedia]] – general definition and historical mention of reload thunk. 
 +  * [[https://hackernoon.com/win3mu-part-5-windows-3-executable-files-2b072fd7716b|Win3mu Part 5 – Windows 3 Executable Files (HackerNoon)]] – detailed analysis of NE files and relocation.