source: trunk/src/kernel32/thunk.cpp@ 2678

Last change on this file since 2678 was 2678, checked in by sandervl, 26 years ago

CB: Ported Wine thunk apis

File size: 13.4 KB
Line 
1/* $Id: thunk.cpp,v 1.3 2000-02-07 22:36:16 sandervl Exp $ */
2
3/*
4 * Win32 thunking API functions (mostly stubs)
5 *
6 * Copyright 1998 Patrick Haller (stubs + Wine port) (?)
7 *
8 * Original WINE code (win32\kernel32.c)
9 *
10 * KERNEL32 thunks and other undocumented stuff
11 *
12 * Copyright 1997-1998 Marcus Meissner
13 * Copyright 1998 Ulrich Weigand
14 * Copyright 1995 Alexandre Julliard
15 *
16 * Project Odin Software License can be found in LICENSE.TXT
17 *
18 */
19#include <os2win.h>
20#include <string.h>
21#include <builtin.h>
22#include "thunk.h"
23
24//******************************************************************************
25//******************************************************************************
26DWORD WIN32API MapLS(void *address)
27{
28// _interrupt(3);
29 dprintf(("MapLS %X, not supported\n", address));
30 return((DWORD)address);
31}
32/***********************************************************************
33 * UnMapLS (KERNEL32.700)
34 *
35 * Free mapped selector.
36 */
37void WIN32API UnMapLS( SEGPTR sptr )
38{
39 dprintf(("UnMapLS - stub\n"));
40#if 0
41 if (SELECTOROF(sptr))
42 SELECTOR_FreeBlock( SELECTOROF(sptr), 1 );
43#endif
44}
45//******************************************************************************
46//******************************************************************************
47DWORD WIN32API ThunkProc(DWORD arg1)
48{
49 dprintf(("ThunkProc - stub\n"));
50 return(0);
51}
52//******************************************************************************
53//******************************************************************************
54void WIN32API FT_Prolog(CONTEXT *context)
55{
56 dprintf(("FT_Prolog - stub\n"));
57}
58/**********************************************************************
59 * FT_Thunk (KERNEL32.234)
60 *
61 * This routine performs the actual call to 16-bit code,
62 * similar to QT_Thunk. The differences are:
63 * - The call target is taken from the buffer created by FT_Prolog
64 * - Those arguments requested by the thunk code (by setting the
65 * corresponding bit in the bitmap at EBP-20) are converted
66 * from 32-bit pointers to segmented pointers (those pointers
67 * are guaranteed to point to structures copied to the stack
68 * by the thunk code, so we always use the 16-bit stack selector
69 * for those addresses).
70 *
71 * The bit #i of EBP-20 corresponds here to the DWORD starting at
72 * ESP+4 + 2*i.
73 *
74 * FIXME: It is unclear what happens if there are more than 32 WORDs
75 * of arguments, so that the single DWORD bitmap is no longer
76 * sufficient ...
77 */
78void WINAPI FT_Thunk( CONTEXT86 *context )
79{
80 DWORD mapESPrelative = *(DWORD *)(EBP_reg(context) - 20);
81 DWORD callTarget = *(DWORD *)(EBP_reg(context) - 52);
82
83 CONTEXT86 context16;
84 DWORD i, argsize;
85 LPBYTE newstack, oldstack;
86
87 dprintf(("FT_Thunk - stub\n"));
88
89#if 0
90 memcpy(&context16,context,sizeof(context16));
91
92 CS_reg(&context16) = HIWORD(callTarget);
93 EIP_reg(&context16) = LOWORD(callTarget);
94 EBP_reg(&context16) = OFFSETOF( NtCurrentTeb()->cur_stack )
95 + (WORD)&((STACK16FRAME*)0)->bp;
96
97 argsize = EBP_reg(context)-ESP_reg(context)-0x40;
98 newstack = (LPBYTE)CURRENT_STACK16 - argsize;
99 oldstack = (LPBYTE)ESP_reg(context);
100
101 memcpy( newstack, oldstack, argsize );
102
103 for (i = 0; i < 32; i++) /* NOTE: What about > 32 arguments? */
104 if (mapESPrelative & (1 << i))
105 {
106 SEGPTR *arg = (SEGPTR *)(newstack + 2*i);
107 *arg = PTR_SEG_OFF_TO_SEGPTR(SELECTOROF(NtCurrentTeb()->cur_stack),
108 OFFSETOF(NtCurrentTeb()->cur_stack) - argsize
109 + (*(LPBYTE *)arg - oldstack));
110 }
111
112 EAX_reg(context) = Callbacks->CallRegisterShortProc( &context16, argsize );
113 EDX_reg(context) = HIWORD(EAX_reg(context));
114 EAX_reg(context) = LOWORD(EAX_reg(context));
115
116 /* Copy modified buffers back to 32-bit stack */
117 memcpy( oldstack, newstack, argsize );
118#endif
119}
120
121/**********************************************************************
122 * FT_ExitNN (KERNEL32.218 - 232)
123 *
124 * One of the FT_ExitNN functions is called at the end of the thunk code.
125 * It removes the stack frame created by FT_Prolog, moves the function
126 * return from EBX to EAX (yes, FT_Thunk did use EAX for the return
127 * value, but the thunk code has moved it from EAX to EBX in the
128 * meantime ... :-), restores the caller's EBX, ESI, and EDI registers,
129 * and perform a return to the CALLER of the thunk code (while removing
130 * the given number of arguments from the caller's stack).
131 */
132
133static void FT_Exit(CONTEXT86 *context, int nPopArgs)
134{
135 dprintf(("FT_Exit - stub\n"));
136#if 0
137 /* Return value is in EBX */
138 EAX_reg(context) = EBX_reg(context);
139
140 /* Restore EBX, ESI, and EDI registers */
141 EBX_reg(context) = *(DWORD *)(EBP_reg(context) - 4);
142 ESI_reg(context) = *(DWORD *)(EBP_reg(context) - 8);
143 EDI_reg(context) = *(DWORD *)(EBP_reg(context) - 12);
144
145 /* Clean up stack frame */
146 ESP_reg(context) = EBP_reg(context);
147 EBP_reg(context) = stack32_pop(context);
148
149 /* Pop return address to CALLER of thunk code */
150 EIP_reg(context) = stack32_pop(context);
151 /* Remove arguments */
152 ESP_reg(context) += nPopArgs;
153#endif
154}
155
156void WINAPI FT_Exit0 (CONTEXT86 *context) { FT_Exit(context, 0); }
157void WINAPI FT_Exit4 (CONTEXT86 *context) { FT_Exit(context, 4); }
158void WINAPI FT_Exit8 (CONTEXT86 *context) { FT_Exit(context, 8); }
159void WINAPI FT_Exit12(CONTEXT86 *context) { FT_Exit(context, 12); }
160void WINAPI FT_Exit16(CONTEXT86 *context) { FT_Exit(context, 16); }
161void WINAPI FT_Exit20(CONTEXT86 *context) { FT_Exit(context, 20); }
162void WINAPI FT_Exit24(CONTEXT86 *context) { FT_Exit(context, 24); }
163void WINAPI FT_Exit28(CONTEXT86 *context) { FT_Exit(context, 28); }
164void WINAPI FT_Exit32(CONTEXT86 *context) { FT_Exit(context, 32); }
165void WINAPI FT_Exit36(CONTEXT86 *context) { FT_Exit(context, 36); }
166void WINAPI FT_Exit40(CONTEXT86 *context) { FT_Exit(context, 40); }
167void WINAPI FT_Exit44(CONTEXT86 *context) { FT_Exit(context, 44); }
168void WINAPI FT_Exit48(CONTEXT86 *context) { FT_Exit(context, 48); }
169void WINAPI FT_Exit52(CONTEXT86 *context) { FT_Exit(context, 52); }
170void WINAPI FT_Exit56(CONTEXT86 *context) { FT_Exit(context, 56); }
171/**********************************************************************
172 * QT_Thunk (KERNEL32)
173 *
174 * The target address is in EDX.
175 * The 16 bit arguments start at ESP+4.
176 * The number of 16bit argumentbytes is EBP-ESP-0x44 (68 Byte thunksetup).
177 * [ok]
178 */
179VOID WIN32API QT_Thunk(CONTEXT *context)
180{
181 dprintf(("QT_Thunk\n"));
182#if 0
183 CONTEXT context16;
184 DWORD argsize;
185
186 memcpy(&context16,context,sizeof(context16));
187
188 CS_reg(&context16) = HIWORD(EDX_reg(context));
189 IP_reg(&context16) = LOWORD(EDX_reg(context));
190
191 argsize = EBP_reg(context)-ESP_reg(context)-0x44;
192
193 /* additional 4 bytes used by the relaycode for storing the stackptr */
194 memcpy( ((LPBYTE)CURRENT_STACK16)-argsize-4,
195 (LPBYTE)ESP_reg(context)+4,
196 argsize
197 );
198 EAX_reg(context) = CallTo16_regs_short(&context16,-argsize);
199#endif
200}
201//******************************************************************************
202/***********************************************************************
203 * Generates a FT_Prolog call.
204 *
205 * 0FB6D1 movzbl edx,cl
206 * 8B1495xxxxxxxx mov edx,[4*edx + xxxxxxxx]
207 * 68xxxxxxxx push FT_Prolog
208 * C3 lret
209 */
210static void _write_ftprolog(LPBYTE thunk,DWORD thunkstart)
211{
212 LPBYTE x;
213
214 x = thunk;
215 *x++ = 0x0f;*x++=0xb6;*x++=0xd1; /* movzbl edx,cl */
216 *x++ = 0x8B;*x++=0x14;*x++=0x95;*(DWORD*)x= thunkstart;
217 x+=4; /* mov edx, [4*edx + thunkstart] */
218 *x++ = 0x68; *(DWORD*)x = (DWORD)FT_Prolog;
219 x+=4; /* push FT_Prolog */
220 *x++ = 0xC3; /* lret */
221 /* fill rest with 0xCC / int 3 */
222}
223//******************************************************************************
224/***********************************************************************
225 * Generates a QT_Thunk style call.
226 *
227 * 33C9 xor ecx, ecx
228 * 8A4DFC mov cl , [ebp-04]
229 * 8B148Dxxxxxxxx mov edx, [4*ecx + (EAX+EDX)]
230 * B8yyyyyyyy mov eax, QT_Thunk
231 * FFE0 jmp eax
232 */
233static void _write_qtthunk(LPBYTE start,DWORD thunkstart)
234{
235 LPBYTE x;
236
237 x = start;
238 *x++ = 0x33;*x++=0xC9; /* xor ecx,ecx */
239 *x++ = 0x8A;*x++=0x4D;*x++=0xFC; /* movb cl,[ebp-04] */
240 *x++ = 0x8B;*x++=0x14;*x++=0x8D;*(DWORD*)x= thunkstart;
241 x+=4; /* mov edx, [4*ecx + (EAX+EDX) */
242 *x++ = 0xB8; *(DWORD*)x = (DWORD)QT_Thunk;
243 x+=4; /* mov eax , QT_Thunk */
244 *x++ = 0xFF; *x++ = 0xE0; /* jmp eax */
245 /* should fill the rest of the 32 bytes with 0xCC */
246}
247
248//******************************************************************************
249//******************************************************************************
250DWORD WIN32API ThunkConnect32(thunkstruct *ths, LPSTR thunkfun16,
251 LPSTR module16, LPSTR module32, HMODULE hmod32,
252 DWORD dllinitarg1 )
253{
254 thunkstruct *ths16;
255
256// _interrupt(3);
257 dprintf(("ThunkConnect32 %s %s %s not supported\n", thunkfun16, module16, module32));
258
259 if(strncmp(ths->magic,"SL01",4) && strncmp(ths->magic,"LS01",4))
260 return 0;
261
262 ths16 = (thunkstruct *)LocalAlloc(LPTR, ths->length);
263 ths16->length = ths->length;
264 ths16->ptr = (DWORD)ThunkProc;
265
266 if(!strncmp(ths->magic,"SL01",4)) {
267 ths->x0C = (DWORD)ths16;
268 *(DWORD *)ths16->magic = 0x0000304C;
269 }
270 if(!strncmp(ths->magic,"LS01",4)) {
271 ths->ptr = ths16->ptr;
272 /* code offset for QT_Thunk is at 0x1C... */
273 _write_qtthunk (((LPBYTE)ths) + ths->x1C,ths->ptr);
274
275 /* code offset for FT_Prolog is at 0x20... */
276 _write_ftprolog(((LPBYTE)ths) + ths->x20,ths->ptr);
277 return 1;
278 }
279 return TRUE;
280}
281//******************************************************************************
282//******************************************************************************
283DWORD WIN32API K32Thk1632Prolog(DWORD arg1)
284{
285 dprintf(("OS2K32Thk1632Prolog %X not supported\n", arg1));
286 return(0);
287}
288//******************************************************************************
289//******************************************************************************
290DWORD WIN32API K32Thk1632Epilog(DWORD arg1)
291{
292 dprintf(("K32Thk1632Epilog %X not supported\n", arg1));
293 return(0);
294}
295//******************************************************************************
296//******************************************************************************
297DWORD WIN32API MapSLFix(DWORD arg1)
298{
299 dprintf(("MapSLFix %X not supported\n", arg1));
300 return(0);
301}
302/***********************************************************************
303 * UnMapSLFixArray (KERNEL32.701)
304 */
305void WIN32API UnMapSLFixArray( SEGPTR sptr[], INT length, CONTEXT86 *context )
306{
307 /* Must not change EAX, hence defined as 'register' function */
308}
309/**********************************************************************
310 * SMapLS* (KERNEL32)
311 * These functions map linear pointers at [EBP+xxx] to segmented pointers
312 * and return them.
313 * Win95 uses some kind of alias structs, which it stores in [EBP+x] to
314 * unravel them at SUnMapLS. We just store the segmented pointer there.
315 */
316static void
317x_SMapLS_IP_EBP_x(CONTEXT86 *context,int argoff) {
318 DWORD val,ptr;
319
320 val =*(DWORD*)(EBP_reg(context)+argoff);
321 if (val<0x10000) {
322 ptr=val;
323 *(DWORD*)(EBP_reg(context)+argoff) = 0;
324 } else {
325 ptr = MapLS((LPVOID)val);
326 *(DWORD*)(EBP_reg(context)+argoff) = ptr;
327 }
328 EAX_reg(context) = ptr;
329}
330
331void WINAPI SMapLS_IP_EBP_8 (CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context, 8);}
332void WINAPI SMapLS_IP_EBP_12(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,12);}
333void WINAPI SMapLS_IP_EBP_16(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,16);}
334void WINAPI SMapLS_IP_EBP_20(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,20);}
335void WINAPI SMapLS_IP_EBP_24(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,24);}
336void WINAPI SMapLS_IP_EBP_28(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,28);}
337void WINAPI SMapLS_IP_EBP_32(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,32);}
338void WINAPI SMapLS_IP_EBP_36(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,36);}
339void WINAPI SMapLS_IP_EBP_40(CONTEXT86 *context) {x_SMapLS_IP_EBP_x(context,40);}
340
341void WINAPI SMapLS( CONTEXT86 *context )
342{
343 if (EAX_reg(context)>=0x10000) {
344 EAX_reg(context) = MapLS((LPVOID)EAX_reg(context));
345 EDX_reg(context) = EAX_reg(context);
346 } else {
347 EDX_reg(context) = 0;
348 }
349}
350
351void WINAPI SUnMapLS( CONTEXT86 *context )
352{
353 if (EAX_reg(context)>=0x10000)
354 UnMapLS((SEGPTR)EAX_reg(context));
355}
356
357static void
358x_SUnMapLS_IP_EBP_x(CONTEXT86 *context,int argoff) {
359 if (*(DWORD*)(EBP_reg(context)+argoff))
360 UnMapLS(*(DWORD*)(EBP_reg(context)+argoff));
361 *(DWORD*)(EBP_reg(context)+argoff)=0;
362}
363void WINAPI SUnMapLS_IP_EBP_8 (CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context, 8); }
364void WINAPI SUnMapLS_IP_EBP_12(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,12); }
365void WINAPI SUnMapLS_IP_EBP_16(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,16); }
366void WINAPI SUnMapLS_IP_EBP_20(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,20); }
367void WINAPI SUnMapLS_IP_EBP_24(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,24); }
368void WINAPI SUnMapLS_IP_EBP_28(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,28); }
369void WINAPI SUnMapLS_IP_EBP_32(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,32); }
370void WINAPI SUnMapLS_IP_EBP_36(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,36); }
371void WINAPI SUnMapLS_IP_EBP_40(CONTEXT86 *context) { x_SUnMapLS_IP_EBP_x(context,40); }
372
Note: See TracBrowser for help on using the repository browser.