Release 1.5.29.
[wine] / tools / winebuild / relay.c
1 /*
2  * Relay calls helper routines
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995 Martin von Loewis
6  * Copyright 1995, 1996, 1997 Alexandre Julliard
7  * Copyright 1997 Eric Youngdale
8  * Copyright 1999 Ulrich Weigand
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <ctype.h>
29 #include <stdarg.h>
30
31 #include "build.h"
32
33 /* offset of the stack pointer relative to %fs:(0) */
34 #define STACKOFFSET 0xc0  /* FIELD_OFFSET(TEB,WOW32Reserved) */
35
36 /* fix this if the ntdll_thread_regs structure is changed */
37 #define GS_OFFSET  0x1d8  /* FIELD_OFFSET(TEB,SystemReserved2) + FIELD_OFFSET(ntdll_thread_data,gs) */
38
39 #define DPMI_VIF_OFFSET      (0x1fc + 0) /* FIELD_OFFSET(TEB,GdiTebBatch) + FIELD_OFFSET(WINE_VM86_TEB_INFO,dpmi_vif) */
40 #define VM86_PENDING_OFFSET  (0x1fc + 4) /* FIELD_OFFSET(TEB,GdiTebBatch) + FIELD_OFFSET(WINE_VM86_TEB_INFO,vm86_pending) */
41
42 static void function_header( const char *name )
43 {
44     output( "\n\t.align %d\n", get_alignment(4) );
45     output( "\t%s\n", func_declaration(name) );
46     output( "%s\n", asm_globl(name) );
47 }
48
49
50 /*******************************************************************
51  *         BuildCallFrom16Core
52  *
53  * This routine builds the core routines used in 16->32 thunks:
54  * CallFrom16Word, CallFrom16Long, CallFrom16Register, and CallFrom16Thunk.
55  *
56  * These routines are intended to be called via a far call (with 32-bit
57  * operand size) from 16-bit code.  The 16-bit code stub must push %bp,
58  * the 32-bit entry point to be called, and the argument conversion
59  * routine to be used (see stack layout below).
60  *
61  * The core routine completes the STACK16FRAME on the 16-bit stack and
62  * switches to the 32-bit stack.  Then, the argument conversion routine
63  * is called; it gets passed the 32-bit entry point and a pointer to the
64  * 16-bit arguments (on the 16-bit stack) as parameters. (You can either
65  * use conversion routines automatically generated by BuildCallFrom16,
66  * or write your own for special purposes.)
67  *
68  * The conversion routine must call the 32-bit entry point, passing it
69  * the converted arguments, and return its return value to the core.
70  * After the conversion routine has returned, the core switches back
71  * to the 16-bit stack, converts the return value to the DX:AX format
72  * (CallFrom16Long), and returns to the 16-bit call stub.  All parameters,
73  * including %bp, are popped off the stack.
74  *
75  * The 16-bit call stub now returns to the caller, popping the 16-bit
76  * arguments if necessary (pascal calling convention).
77  *
78  * In the case of a 'register' function, CallFrom16Register fills a
79  * CONTEXT86 structure with the values all registers had at the point
80  * the first instruction of the 16-bit call stub was about to be
81  * executed.  A pointer to this CONTEXT86 is passed as third parameter
82  * to the argument conversion routine, which typically passes it on
83  * to the called 32-bit entry point.
84  *
85  * CallFrom16Thunk is a special variant used by the implementation of
86  * the Win95 16->32 thunk functions C16ThkSL and C16ThkSL01 and is
87  * implemented as follows:
88  * On entry, the EBX register is set up to contain a flat pointer to the
89  * 16-bit stack such that EBX+22 points to the first argument.
90  * Then, the entry point is called, while EBP is set up to point
91  * to the return address (on the 32-bit stack).
92  * The called function returns with CX set to the number of bytes
93  * to be popped of the caller's stack.
94  *
95  * Stack layout upon entry to the core routine (STACK16FRAME):
96  *  ...           ...
97  * (sp+24) word   first 16-bit arg
98  * (sp+22) word   cs
99  * (sp+20) word   ip
100  * (sp+18) word   bp
101  * (sp+14) long   32-bit entry point (reused for Win16 mutex recursion count)
102  * (sp+12) word   ip of actual entry point (necessary for relay debugging)
103  * (sp+8)  long   relay (argument conversion) function entry point
104  * (sp+4)  long   cs of 16-bit entry point
105  * (sp)    long   ip of 16-bit entry point
106  *
107  * Added on the stack:
108  * (sp-2)  word   saved gs
109  * (sp-4)  word   saved fs
110  * (sp-6)  word   saved es
111  * (sp-8)  word   saved ds
112  * (sp-12) long   saved ebp
113  * (sp-16) long   saved ecx
114  * (sp-20) long   saved edx
115  * (sp-24) long   saved previous stack
116  */
117 static void BuildCallFrom16Core( int reg_func, int thunk )
118 {
119     /* Function header */
120     if (thunk) function_header( "__wine_call_from_16_thunk" );
121     else if (reg_func) function_header( "__wine_call_from_16_regs" );
122     else function_header( "__wine_call_from_16" );
123
124     /* Create STACK16FRAME (except STACK32FRAME link) */
125     output( "\tpushw %%gs\n" );
126     output( "\tpushw %%fs\n" );
127     output( "\tpushw %%es\n" );
128     output( "\tpushw %%ds\n" );
129     output( "\tpushl %%ebp\n" );
130     output( "\tpushl %%ecx\n" );
131     output( "\tpushl %%edx\n" );
132
133     /* Save original EFlags register */
134     if (reg_func) output( "\tpushfl\n" );
135
136     if ( UsePIC )
137     {
138         output( "\tcall 1f\n" );
139         output( "1:\tpopl %%ecx\n" );
140         output( "\t.byte 0x2e\n\tmovl %s-1b(%%ecx),%%edx\n", asm_name("CallTo16_DataSelector") );
141     }
142     else
143         output( "\t.byte 0x2e\n\tmovl %s,%%edx\n", asm_name("CallTo16_DataSelector") );
144
145     /* Load 32-bit segment registers */
146     output( "\tmovw %%dx, %%ds\n" );
147     output( "\tmovw %%dx, %%es\n" );
148
149     if ( UsePIC )
150         output( "\tmovw %s-1b(%%ecx), %%fs\n", asm_name("CallTo16_TebSelector") );
151     else
152         output( "\tmovw %s, %%fs\n", asm_name("CallTo16_TebSelector") );
153
154     output( "\t.byte 0x64\n\tmov (%d),%%gs\n", GS_OFFSET );
155
156     /* Translate STACK16FRAME base to flat offset in %edx */
157     output( "\tmovw %%ss, %%dx\n" );
158     output( "\tandl $0xfff8, %%edx\n" );
159     output( "\tshrl $1, %%edx\n" );
160     if (UsePIC)
161     {
162         output( "\taddl wine_ldt_copy_ptr-1b(%%ecx),%%edx\n" );
163         output( "\tmovl (%%edx), %%edx\n" );
164     }
165     else
166         output( "\tmovl %s(%%edx), %%edx\n", asm_name("wine_ldt_copy") );
167     output( "\tmovzwl %%sp, %%ebp\n" );
168     output( "\tleal %d(%%ebp,%%edx), %%edx\n", reg_func ? 0 : -4 );
169
170     /* Get saved flags into %ecx */
171     if (reg_func) output( "\tpopl %%ecx\n" );
172
173     /* Get the 32-bit stack pointer from the TEB and complete STACK16FRAME */
174     output( "\t.byte 0x64\n\tmovl (%d), %%ebp\n", STACKOFFSET );
175     output( "\tpushl %%ebp\n" );
176
177     /* Switch stacks */
178     output( "\t.byte 0x64\n\tmovw %%ss, (%d)\n", STACKOFFSET + 2 );
179     output( "\t.byte 0x64\n\tmovw %%sp, (%d)\n", STACKOFFSET );
180     output( "\tpushl %%ds\n" );
181     output( "\tpopl %%ss\n" );
182     output( "\tmovl %%ebp, %%esp\n" );
183     output( "\taddl $0x20,%%ebp\n");  /* FIELD_OFFSET(STACK32FRAME,ebp) */
184
185
186     /* At this point:
187        STACK16FRAME is completely set up
188        DS, ES, SS: flat data segment
189        FS: current TEB
190        ESP: points to last STACK32FRAME
191        EBP: points to ebp member of last STACK32FRAME
192        EDX: points to current STACK16FRAME
193        ECX: contains saved flags
194        all other registers: unchanged */
195
196     /* Special case: C16ThkSL stub */
197     if ( thunk )
198     {
199         /* Set up registers as expected and call thunk */
200         output( "\tleal 0x1a(%%edx),%%ebx\n" );  /* sizeof(STACK16FRAME)-22 */
201         output( "\tleal -4(%%esp), %%ebp\n" );
202
203         output( "\tcall *0x26(%%edx)\n");  /* FIELD_OFFSET(STACK16FRAME,entry_point) */
204
205         /* Switch stack back */
206         output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
207         output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
208         output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
209
210         /* Restore registers and return directly to caller */
211         output( "\taddl $8, %%esp\n" );
212         output( "\tpopl %%ebp\n" );
213         output( "\tpopw %%ds\n" );
214         output( "\tpopw %%es\n" );
215         output( "\tpopw %%fs\n" );
216         output( "\tpopw %%gs\n" );
217         output( "\taddl $20, %%esp\n" );
218
219         output( "\txorb %%ch, %%ch\n" );
220         output( "\tpopl %%ebx\n" );
221         output( "\taddw %%cx, %%sp\n" );
222         output( "\tpush %%ebx\n" );
223
224         output( "\t.byte 0x66\n" );
225         output( "\tlret\n" );
226
227         output_function_size( "__wine_call_from_16_thunk" );
228         return;
229     }
230
231
232     /* Build register CONTEXT */
233     if ( reg_func )
234     {
235         output( "\tsubl $0x2cc,%%esp\n" );       /* sizeof(CONTEXT86) */
236
237         output( "\tmovl %%ecx,0xc0(%%esp)\n" );  /* EFlags */
238
239         output( "\tmovl %%eax,0xb0(%%esp)\n" );  /* Eax */
240         output( "\tmovl %%ebx,0xa4(%%esp)\n" );  /* Ebx */
241         output( "\tmovl %%esi,0xa0(%%esp)\n" );  /* Esi */
242         output( "\tmovl %%edi,0x9c(%%esp)\n" );  /* Edi */
243
244         output( "\tmovl 0x0c(%%edx),%%eax\n");   /* FIELD_OFFSET(STACK16FRAME,ebp) */
245         output( "\tmovl %%eax,0xb4(%%esp)\n" );  /* Ebp */
246         output( "\tmovl 0x08(%%edx),%%eax\n");   /* FIELD_OFFSET(STACK16FRAME,ecx) */
247         output( "\tmovl %%eax,0xac(%%esp)\n" );  /* Ecx */
248         output( "\tmovl 0x04(%%edx),%%eax\n");   /* FIELD_OFFSET(STACK16FRAME,edx) */
249         output( "\tmovl %%eax,0xa8(%%esp)\n" );  /* Edx */
250
251         output( "\tmovzwl 0x10(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ds) */
252         output( "\tmovl %%eax,0x98(%%esp)\n" );  /* SegDs */
253         output( "\tmovzwl 0x12(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,es) */
254         output( "\tmovl %%eax,0x94(%%esp)\n" );  /* SegEs */
255         output( "\tmovzwl 0x14(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,fs) */
256         output( "\tmovl %%eax,0x90(%%esp)\n" );  /* SegFs */
257         output( "\tmovzwl 0x16(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,gs) */
258         output( "\tmovl %%eax,0x8c(%%esp)\n" );  /* SegGs */
259
260         output( "\tmovzwl 0x2e(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,cs) */
261         output( "\tmovl %%eax,0xbc(%%esp)\n" );  /* SegCs */
262         output( "\tmovzwl 0x2c(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ip) */
263         output( "\tmovl %%eax,0xb8(%%esp)\n" );  /* Eip */
264
265         output( "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET+2 );
266         output( "\tmovl %%eax,0xc8(%%esp)\n" );  /* SegSs */
267         output( "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET );
268         output( "\taddl $0x2c,%%eax\n");         /* FIELD_OFFSET(STACK16FRAME,ip) */
269         output( "\tmovl %%eax,0xc4(%%esp)\n" );  /* Esp */
270 #if 0
271         output( "\tfsave 0x1c(%%esp)\n" ); /* FloatSave */
272 #endif
273
274         /* Push address of CONTEXT86 structure -- popped by the relay routine */
275         output( "\tmovl %%esp,%%eax\n" );
276         output( "\tandl $~15,%%esp\n" );
277         output( "\tsubl $4,%%esp\n" );
278         output( "\tpushl %%eax\n" );
279     }
280     else
281     {
282         output( "\tsubl $8,%%esp\n" );
283         output( "\tandl $~15,%%esp\n" );
284         output( "\taddl $8,%%esp\n" );
285     }
286
287     /* Call relay routine (which will call the API entry point) */
288     output( "\tleal 0x30(%%edx),%%eax\n" ); /* sizeof(STACK16FRAME) */
289     output( "\tpushl %%eax\n" );
290     output( "\tpushl 0x26(%%edx)\n");  /* FIELD_OFFSET(STACK16FRAME,entry_point) */
291     output( "\tcall *0x20(%%edx)\n");  /* FIELD_OFFSET(STACK16FRAME,relay) */
292
293     if ( reg_func )
294     {
295         output( "\tleal -748(%%ebp),%%ebx\n" ); /* sizeof(CONTEXT) + FIELD_OFFSET(STACK32FRAME,ebp) */
296
297         /* Switch stack back */
298         output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
299         output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
300         output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
301
302         /* Get return address to CallFrom16 stub */
303         output( "\taddw $0x14,%%sp\n" ); /* FIELD_OFFSET(STACK16FRAME,callfrom_ip)-4 */
304         output( "\tpopl %%eax\n" );
305         output( "\tpopl %%edx\n" );
306
307         /* Restore all registers from CONTEXT */
308         output( "\tmovw 0xc8(%%ebx),%%ss\n");   /* SegSs */
309         output( "\tmovl 0xc4(%%ebx),%%esp\n");  /* Esp */
310         output( "\taddl $4, %%esp\n" );  /* room for final return address */
311
312         output( "\tpushw 0xbc(%%ebx)\n");  /* SegCs */
313         output( "\tpushw 0xb8(%%ebx)\n");  /* Eip */
314         output( "\tpushl %%edx\n" );
315         output( "\tpushl %%eax\n" );
316         output( "\tpushl 0xc0(%%ebx)\n");  /* EFlags */
317         output( "\tpushl 0x98(%%ebx)\n");  /* SegDs */
318
319         output( "\tpushl 0x94(%%ebx)\n");  /* SegEs */
320         output( "\tpopl %%es\n" );
321         output( "\tpushl 0x90(%%ebx)\n");  /* SegFs */
322         output( "\tpopl %%fs\n" );
323         output( "\tpushl 0x8c(%%ebx)\n");  /* SegGs */
324         output( "\tpopl %%gs\n" );
325
326         output( "\tmovl 0xb4(%%ebx),%%ebp\n");  /* Ebp */
327         output( "\tmovl 0xa0(%%ebx),%%esi\n");  /* Esi */
328         output( "\tmovl 0x9c(%%ebx),%%edi\n");  /* Edi */
329         output( "\tmovl 0xb0(%%ebx),%%eax\n");  /* Eax */
330         output( "\tmovl 0xa8(%%ebx),%%edx\n");  /* Edx */
331         output( "\tmovl 0xac(%%ebx),%%ecx\n");  /* Ecx */
332         output( "\tmovl 0xa4(%%ebx),%%ebx\n");  /* Ebx */
333
334         output( "\tpopl %%ds\n" );
335         output( "\tpopfl\n" );
336         output( "\tlret\n" );
337
338         output_function_size( "__wine_call_from_16_regs" );
339     }
340     else
341     {
342         /* Switch stack back */
343         output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
344         output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
345         output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
346
347         /* Restore registers */
348         output( "\tpopl %%edx\n" );
349         output( "\tpopl %%ecx\n" );
350         output( "\tpopl %%ebp\n" );
351         output( "\tpopw %%ds\n" );
352         output( "\tpopw %%es\n" );
353         output( "\tpopw %%fs\n" );
354         output( "\tpopw %%gs\n" );
355
356         /* Return to return stub which will return to caller */
357         output( "\tlret $12\n" );
358
359         output_function_size( "__wine_call_from_16" );
360     }
361 }
362
363
364 /*******************************************************************
365  *         BuildCallTo16Core
366  *
367  * This routine builds the core routines used in 32->16 thunks:
368  *
369  * extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler );
370  * extern void WINAPI wine_call_to_16_regs( CONTEXT86 *context, DWORD cbArgs, PEXCEPTION_HANDLER handler );
371  *
372  * These routines can be called directly from 32-bit code.
373  *
374  * All routines expect that the 16-bit stack contents (arguments) and the
375  * return address (segptr to CallTo16_Ret) were already set up by the
376  * caller; nb_args must contain the number of bytes to be conserved.  The
377  * 16-bit SS:SP will be set accordingly.
378  *
379  * All other registers are either taken from the CONTEXT86 structure
380  * or else set to default values.  The target routine address is either
381  * given directly or taken from the CONTEXT86.
382  */
383 static void BuildCallTo16Core( int reg_func )
384 {
385     const char *name = reg_func ? "wine_call_to_16_regs" : "wine_call_to_16";
386
387     /* Function header */
388     function_header( name );
389
390     /* Function entry sequence */
391     output_cfi( ".cfi_startproc" );
392     output( "\tpushl %%ebp\n" );
393     output_cfi( ".cfi_adjust_cfa_offset 4" );
394     output_cfi( ".cfi_rel_offset %%ebp,0" );
395     output( "\tmovl %%esp, %%ebp\n" );
396     output_cfi( ".cfi_def_cfa_register %%ebp" );
397
398     /* Save the 32-bit registers */
399     output( "\tpushl %%ebx\n" );
400     output_cfi( ".cfi_rel_offset %%ebx,-4" );
401     output( "\tpushl %%esi\n" );
402     output_cfi( ".cfi_rel_offset %%esi,-8" );
403     output( "\tpushl %%edi\n" );
404     output_cfi( ".cfi_rel_offset %%edi,-12" );
405     output( "\t.byte 0x64\n\tmov %%gs,(%d)\n", GS_OFFSET );
406
407     /* Setup exception frame */
408     output( "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET );
409     output( "\tpushl 16(%%ebp)\n" ); /* handler */
410     output( "\t.byte 0x64\n\tpushl (0)\n" );
411     output( "\t.byte 0x64\n\tmovl %%esp,(0)\n" );
412
413     /* Call the actual CallTo16 routine (simulate a lcall) */
414     output( "\tpushl %%cs\n" );
415     output( "\tcall .L%s\n", name );
416
417     /* Remove exception frame */
418     output( "\t.byte 0x64\n\tpopl (0)\n" );
419     output( "\taddl $4, %%esp\n" );
420     output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
421
422     if ( !reg_func )
423     {
424         /* Convert return value */
425         output( "\tandl $0xffff,%%eax\n" );
426         output( "\tshll $16,%%edx\n" );
427         output( "\torl %%edx,%%eax\n" );
428     }
429     else
430     {
431         /*
432          * Modify CONTEXT86 structure to contain new values
433          *
434          * NOTE:  We restore only EAX, EBX, EDX, EDX, EBP, and ESP.
435          *        The segment registers as well as ESI and EDI should
436          *        not be modified by a well-behaved 16-bit routine in
437          *        any case.  [If necessary, we could restore them as well,
438          *        at the cost of a somewhat less efficient return path.]
439          */
440
441         output( "\tmovl 0x14(%%esp),%%edi\n" ); /* FIELD_OFFSET(STACK32FRAME,target) - FIELD_OFFSET(STACK32FRAME,edi) */
442                 /* everything above edi has been popped already */
443
444         output( "\tmovl %%eax,0xb0(%%edi)\n");  /* Eax */
445         output( "\tmovl %%ebx,0xa4(%%edi)\n");  /* Ebx */
446         output( "\tmovl %%ecx,0xac(%%edi)\n");  /* Ecx */
447         output( "\tmovl %%edx,0xa8(%%edi)\n");  /* Edx */
448         output( "\tmovl %%ebp,0xb4(%%edi)\n");  /* Ebp */
449         output( "\tmovl %%esi,0xc4(%%edi)\n");  /* Esp */
450                  /* The return glue code saved %esp into %esi */
451     }
452
453     /* Restore the 32-bit registers */
454     output( "\tpopl %%edi\n" );
455     output_cfi( ".cfi_same_value %%edi" );
456     output( "\tpopl %%esi\n" );
457     output_cfi( ".cfi_same_value %%esi" );
458     output( "\tpopl %%ebx\n" );
459     output_cfi( ".cfi_same_value %%ebx" );
460
461     /* Function exit sequence */
462     output( "\tpopl %%ebp\n" );
463     output_cfi( ".cfi_def_cfa %%esp,4" );
464     output_cfi( ".cfi_same_value %%ebp" );
465     output( "\tret $12\n" );
466     output_cfi( ".cfi_endproc" );
467
468
469     /* Start of the actual CallTo16 routine */
470
471     output( ".L%s:\n", name );
472
473     /* Switch to the 16-bit stack */
474     output( "\tmovl %%esp,%%edx\n" );
475     output( "\t.byte 0x64\n\tmovw (%d),%%ss\n", STACKOFFSET + 2);
476     output( "\t.byte 0x64\n\tmovw (%d),%%sp\n", STACKOFFSET );
477     output( "\t.byte 0x64\n\tmovl %%edx,(%d)\n", STACKOFFSET );
478
479     /* Make %bp point to the previous stackframe (built by CallFrom16) */
480     output( "\tmovzwl %%sp,%%ebp\n" );
481     output( "\tleal 0x2a(%%ebp),%%ebp\n");  /* FIELD_OFFSET(STACK16FRAME,bp) */
482
483     /* Add the specified offset to the new sp */
484     output( "\tsubw 0x2c(%%edx), %%sp\n");  /* FIELD_OFFSET(STACK32FRAME,nb_args) */
485
486     if (reg_func)
487     {
488         /* Push the called routine address */
489         output( "\tmovl 0x28(%%edx),%%edx\n");  /* FIELD_OFFSET(STACK32FRAME,target) */
490         output( "\tpushw 0xbc(%%edx)\n");  /* SegCs */
491         output( "\tpushw 0xb8(%%edx)\n");  /* Eip */
492
493         /* Get the registers */
494         output( "\tpushw 0x98(%%edx)\n");  /* SegDs */
495         output( "\tpushl 0x94(%%edx)\n");  /* SegEs */
496         output( "\tpopl %%es\n" );
497         output( "\tpushl 0x90(%%edx)\n");  /* SegFs */
498         output( "\tpopl %%fs\n" );
499         output( "\tpushl 0x8c(%%edx)\n");  /* SegGs */
500         output( "\tpopl %%gs\n" );
501         output( "\tmovl 0xb4(%%edx),%%ebp\n");  /* Ebp */
502         output( "\tmovl 0xa0(%%edx),%%esi\n");  /* Esi */
503         output( "\tmovl 0x9c(%%edx),%%edi\n");  /* Edi */
504         output( "\tmovl 0xb0(%%edx),%%eax\n");  /* Eax */
505         output( "\tmovl 0xa4(%%edx),%%ebx\n");  /* Ebx */
506         output( "\tmovl 0xac(%%edx),%%ecx\n");  /* Ecx */
507         output( "\tmovl 0xa8(%%edx),%%edx\n");  /* Edx */
508
509         /* Get the 16-bit ds */
510         output( "\tpopw %%ds\n" );
511     }
512     else  /* not a register function */
513     {
514         /* Push the called routine address */
515         output( "\tpushl 0x28(%%edx)\n"); /* FIELD_OFFSET(STACK32FRAME,target) */
516
517         /* Set %fs and %gs to the value saved by the last CallFrom16 */
518         output( "\tpushw -22(%%ebp)\n" ); /* FIELD_OFFSET(STACK16FRAME,fs)-FIELD_OFFSET(STACK16FRAME,bp) */
519         output( "\tpopw %%fs\n" );
520         output( "\tpushw -20(%%ebp)\n" ); /* FIELD_OFFSET(STACK16FRAME,gs)-FIELD_OFFSET(STACK16FRAME,bp) */
521         output( "\tpopw %%gs\n" );
522
523         /* Set %ds and %es (and %ax just in case) equal to %ss */
524         output( "\tmovw %%ss,%%ax\n" );
525         output( "\tmovw %%ax,%%ds\n" );
526         output( "\tmovw %%ax,%%es\n" );
527     }
528
529     /* Jump to the called routine */
530     output( "\t.byte 0x66\n" );
531     output( "\tlret\n" );
532
533     /* Function footer */
534     output_function_size( name );
535 }
536
537
538 /*******************************************************************
539  *         BuildRet16Func
540  *
541  * Build the return code for 16-bit callbacks
542  */
543 static void BuildRet16Func(void)
544 {
545     function_header( "__wine_call_to_16_ret" );
546
547     /* Save %esp into %esi */
548     output( "\tmovl %%esp,%%esi\n" );
549
550     /* Restore 32-bit segment registers */
551
552     output( "\t.byte 0x2e\n\tmovl %s", asm_name("CallTo16_DataSelector") );
553     output( "-%s,%%edi\n", asm_name("__wine_call16_start") );
554     output( "\tmovw %%di,%%ds\n" );
555     output( "\tmovw %%di,%%es\n" );
556
557     output( "\t.byte 0x2e\n\tmov %s", asm_name("CallTo16_TebSelector") );
558     output( "-%s,%%fs\n", asm_name("__wine_call16_start") );
559
560     output( "\t.byte 0x64\n\tmov (%d),%%gs\n", GS_OFFSET );
561
562     /* Restore the 32-bit stack */
563
564     output( "\tmovw %%di,%%ss\n" );
565     output( "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET );
566
567     /* Return to caller */
568
569     output( "\tlret\n" );
570     output_function_size( "__wine_call_to_16_ret" );
571 }
572
573
574 /*******************************************************************
575  *         BuildCallTo32CBClient
576  *
577  * Call a CBClient relay stub from 32-bit code (KERNEL.620).
578  *
579  * Since the relay stub is itself 32-bit, this should not be a problem;
580  * unfortunately, the relay stubs are expected to switch back to a
581  * 16-bit stack (and 16-bit code) after completion :-(
582  *
583  * This would conflict with our 16- vs. 32-bit stack handling, so
584  * we simply switch *back* to our 32-bit stack before returning to
585  * the caller ...
586  *
587  * The CBClient relay stub expects to be called with the following
588  * 16-bit stack layout, and with ebp and ebx pointing into the 16-bit
589  * stack at the designated places:
590  *
591  *    ...
592  *  (ebp+14) original arguments to the callback routine
593  *  (ebp+10) far return address to original caller
594  *  (ebp+6)  Thunklet target address
595  *  (ebp+2)  Thunklet relay ID code
596  *  (ebp)    BP (saved by CBClientGlueSL)
597  *  (ebp-2)  SI (saved by CBClientGlueSL)
598  *  (ebp-4)  DI (saved by CBClientGlueSL)
599  *  (ebp-6)  DS (saved by CBClientGlueSL)
600  *
601  *   ...     buffer space used by the 16-bit side glue for temp copies
602  *
603  *  (ebx+4)  far return address to 16-bit side glue code
604  *  (ebx)    saved 16-bit ss:sp (pointing to ebx+4)
605  *
606  * The 32-bit side glue code accesses both the original arguments (via ebp)
607  * and the temporary copies prepared by the 16-bit side glue (via ebx).
608  * After completion, the stub will load ss:sp from the buffer at ebx
609  * and perform a far return to 16-bit code.
610  *
611  * To trick the relay stub into returning to us, we replace the 16-bit
612  * return address to the glue code by a cs:ip pair pointing to our
613  * return entry point (the original return address is saved first).
614  * Our return stub thus called will then reload the 32-bit ss:esp and
615  * return to 32-bit code (by using and ss:esp value that we have also
616  * pushed onto the 16-bit stack before and a cs:eip values found at
617  * that position on the 32-bit stack).  The ss:esp to be restored is
618  * found relative to the 16-bit stack pointer at:
619  *
620  *  (ebx-4)   ss  (flat)
621  *  (ebx-8)   sp  (32-bit stack pointer)
622  *
623  * The second variant of this routine, CALL32_CBClientEx, which is used
624  * to implement KERNEL.621, has to cope with yet another problem: Here,
625  * the 32-bit side directly returns to the caller of the CBClient thunklet,
626  * restoring registers saved by CBClientGlueSL and cleaning up the stack.
627  * As we have to return to our 32-bit code first, we have to adapt the
628  * layout of our temporary area so as to include values for the registers
629  * that are to be restored, and later (in the implementation of KERNEL.621)
630  * we *really* restore them. The return stub restores DS, DI, SI, and BP
631  * from the stack, skips the next 8 bytes (CBClient relay code / target),
632  * and then performs a lret NN, where NN is the number of arguments to be
633  * removed. Thus, we prepare our temporary area as follows:
634  *
635  *     (ebx+22) 16-bit cs  (this segment)
636  *     (ebx+20) 16-bit ip  ('16-bit' return entry point)
637  *     (ebx+16) 32-bit ss  (flat)
638  *     (ebx+12) 32-bit sp  (32-bit stack pointer)
639  *     (ebx+10) 16-bit bp  (points to ebx+24)
640  *     (ebx+8)  16-bit si  (ignored)
641  *     (ebx+6)  16-bit di  (ignored)
642  *     (ebx+4)  16-bit ds  (we actually use the flat DS here)
643  *     (ebx+2)  16-bit ss  (16-bit stack segment)
644  *     (ebx+0)  16-bit sp  (points to ebx+4)
645  *
646  * Note that we ensure that DS is not changed and remains the flat segment,
647  * and the 32-bit stack pointer our own return stub needs fits just
648  * perfectly into the 8 bytes that are skipped by the Windows stub.
649  * One problem is that we have to determine the number of removed arguments,
650  * as these have to be really removed in KERNEL.621. Thus, the BP value
651  * that we place in the temporary area to be restored, contains the value
652  * that SP would have if no arguments were removed. By comparing the actual
653  * value of SP with this value in our return stub we can compute the number
654  * of removed arguments. This is then returned to KERNEL.621.
655  *
656  * The stack layout of this function:
657  * (ebp+20)  nArgs     pointer to variable receiving nr. of args (Ex only)
658  * (ebp+16)  esi       pointer to caller's esi value
659  * (ebp+12)  arg       ebp value to be set for relay stub
660  * (ebp+8)   func      CBClient relay stub address
661  * (ebp+4)   ret addr
662  * (ebp)     ebp
663  */
664 static void BuildCallTo32CBClient( int isEx )
665 {
666     function_header( isEx ? "CALL32_CBClientEx" : "CALL32_CBClient" );
667
668     /* Entry code */
669
670     output_cfi( ".cfi_startproc" );
671     output( "\tpushl %%ebp\n" );
672     output_cfi( ".cfi_adjust_cfa_offset 4" );
673     output_cfi( ".cfi_rel_offset %%ebp,0" );
674     output( "\tmovl %%esp,%%ebp\n" );
675     output_cfi( ".cfi_def_cfa_register %%ebp" );
676     output( "\tpushl %%edi\n" );
677     output_cfi( ".cfi_rel_offset %%edi,-4" );
678     output( "\tpushl %%esi\n" );
679     output_cfi( ".cfi_rel_offset %%esi,-8" );
680     output( "\tpushl %%ebx\n" );
681     output_cfi( ".cfi_rel_offset %%ebx,-12" );
682
683     /* Get pointer to temporary area and save the 32-bit stack pointer */
684
685     output( "\tmovl 16(%%ebp), %%ebx\n" );
686     output( "\tleal -8(%%esp), %%eax\n" );
687
688     if ( !isEx )
689         output( "\tmovl %%eax, -8(%%ebx)\n" );
690     else
691         output( "\tmovl %%eax, 12(%%ebx)\n" );
692
693     /* Set up registers and call CBClient relay stub (simulating a far call) */
694
695     output( "\tmovl 20(%%ebp), %%esi\n" );
696     output( "\tmovl (%%esi), %%esi\n" );
697
698     output( "\tmovl 8(%%ebp), %%eax\n" );
699     output( "\tmovl 12(%%ebp), %%ebp\n" );
700
701     output( "\tpushl %%cs\n" );
702     output( "\tcall *%%eax\n" );
703
704     /* Return new esi value to caller */
705
706     output( "\tmovl 32(%%esp), %%edi\n" );
707     output( "\tmovl %%esi, (%%edi)\n" );
708
709     /* Return argument size to caller */
710     if ( isEx )
711     {
712         output( "\tmovl 36(%%esp), %%ebx\n" );
713         output( "\tmovl %%ebp, (%%ebx)\n" );
714     }
715
716     /* Restore registers and return */
717
718     output( "\tpopl %%ebx\n" );
719     output_cfi( ".cfi_same_value %%ebx" );
720     output( "\tpopl %%esi\n" );
721     output_cfi( ".cfi_same_value %%esi" );
722     output( "\tpopl %%edi\n" );
723     output_cfi( ".cfi_same_value %%edi" );
724     output( "\tpopl %%ebp\n" );
725     output_cfi( ".cfi_def_cfa %%esp,4" );
726     output_cfi( ".cfi_same_value %%ebp" );
727     output( "\tret\n" );
728     output_cfi( ".cfi_endproc" );
729     output_function_size( isEx ? "CALL32_CBClientEx" : "CALL32_CBClient" );
730
731     /* '16-bit' return stub */
732
733     function_header( isEx ? "CALL32_CBClientEx_Ret" : "CALL32_CBClient_Ret" );
734     if ( !isEx )
735     {
736         output( "\tmovzwl %%sp, %%ebx\n" );
737         output( "\tlssl %%ss:-16(%%ebx), %%esp\n" );
738     }
739     else
740     {
741         output( "\tmovzwl %%bp, %%ebx\n" );
742         output( "\tsubw %%bp, %%sp\n" );
743         output( "\tmovzwl %%sp, %%ebp\n" );
744         output( "\tlssl %%ss:-12(%%ebx), %%esp\n" );
745     }
746     output( "\tlret\n" );
747     output_function_size( isEx ? "CALL32_CBClientEx_Ret" : "CALL32_CBClient_Ret" );
748 }
749
750
751 /*******************************************************************
752  *         build_call_from_regs_x86
753  *
754  * Build a 32-bit-to-Wine call-back function for a 'register' function.
755  * 'args' is the number of dword arguments.
756  *
757  * Stack layout:
758  *   ...
759  * (ebp+20)  first arg
760  * (ebp+16)  ret addr to user code
761  * (ebp+12)  func to call (relative to relay code ret addr)
762  * (ebp+8)   number of args
763  * (ebp+4)   ret addr to relay code
764  * (ebp+0)   saved ebp
765  * (ebp-128) buffer area to allow stack frame manipulation
766  * (ebp-332) CONTEXT86 struct
767  * (ebp-336) padding for stack alignment
768  * (ebp-336-n) CONTEXT86 *argument
769  *  ....     other arguments copied from (ebp+12)
770  *
771  * The entry point routine is called with a CONTEXT* extra argument,
772  * following the normal args. In this context structure, EIP_reg
773  * contains the return address to user code, and ESP_reg the stack
774  * pointer on return (with the return address and arguments already
775  * removed).
776  */
777 static void build_call_from_regs_x86(void)
778 {
779     static const int STACK_SPACE = 128 + 0x2cc /* sizeof(CONTEXT86) */;
780
781     /* Function header */
782
783     output( "\t.text\n" );
784     function_header( "__wine_call_from_regs" );
785
786     /* Allocate some buffer space on the stack */
787
788     output_cfi( ".cfi_startproc" );
789     output( "\tpushl %%ebp\n" );
790     output_cfi( ".cfi_adjust_cfa_offset 4" );
791     output_cfi( ".cfi_rel_offset %%ebp,0" );
792     output( "\tmovl %%esp,%%ebp\n" );
793     output_cfi( ".cfi_def_cfa_register %%ebp" );
794     output( "\tleal -%d(%%esp),%%esp\n", STACK_SPACE );
795
796     /* Build the context structure */
797
798     output( "\tmovl %%eax,0xb0(%%esp)\n" );  /* Eax */
799     output( "\tpushfl\n" );
800     output( "\tpopl %%eax\n" );
801     output( "\tmovl %%eax,0xc0(%%esp)\n");  /* EFlags */
802     output( "\tmovl 0(%%ebp),%%eax\n" );
803     output( "\tmovl %%eax,0xb4(%%esp)\n");  /* Ebp */
804     output( "\tmovl %%ebx,0xa4(%%esp)\n");  /* Ebx */
805     output( "\tmovl %%ecx,0xac(%%esp)\n");  /* Ecx */
806     output( "\tmovl %%edx,0xa8(%%esp)\n");  /* Edx */
807     output( "\tmovl %%esi,0xa0(%%esp)\n");  /* Esi */
808     output( "\tmovl %%edi,0x9c(%%esp)\n");  /* Edi */
809
810     output( "\txorl %%eax,%%eax\n" );
811     output( "\tmovw %%cs,%%ax\n" );
812     output( "\tmovl %%eax,0xbc(%%esp)\n");  /* SegCs */
813     output( "\tmovw %%es,%%ax\n" );
814     output( "\tmovl %%eax,0x94(%%esp)\n");  /* SegEs */
815     output( "\tmovw %%fs,%%ax\n" );
816     output( "\tmovl %%eax,0x90(%%esp)\n");  /* SegFs */
817     output( "\tmovw %%gs,%%ax\n" );
818     output( "\tmovl %%eax,0x8c(%%esp)\n");  /* SegGs */
819     output( "\tmovw %%ss,%%ax\n" );
820     output( "\tmovl %%eax,0xc8(%%esp)\n");  /* SegSs */
821     output( "\tmovw %%ds,%%ax\n" );
822     output( "\tmovl %%eax,0x98(%%esp)\n");  /* SegDs */
823     output( "\tmovw %%ax,%%es\n" );  /* set %es equal to %ds just in case */
824
825     output( "\tmovl $0x10007,0(%%esp)\n");  /* ContextFlags */
826
827     output( "\tmovl 16(%%ebp),%%eax\n" ); /* Get %eip at time of call */
828     output( "\tmovl %%eax,0xb8(%%esp)\n");  /* Eip */
829
830     /* Transfer the arguments */
831
832     output( "\tmovl 8(%%ebp),%%ecx\n" );    /* fetch number of args to copy */
833     output( "\tleal 4(,%%ecx,4),%%edx\n" ); /* add 4 for context arg */
834     output( "\tsubl %%edx,%%esp\n" );
835     output( "\tandl $~15,%%esp\n" );
836     output( "\tleal 20(%%ebp),%%esi\n" );  /* get %esp at time of call */
837     output( "\tmovl %%esp,%%edi\n" );
838     output( "\ttest %%ecx,%%ecx\n" );
839     output( "\tjz 1f\n" );
840     output( "\tcld\n" );
841     output( "\trep\n\tmovsl\n" );  /* copy args */
842     output( "1:\tleal %d(%%ebp),%%eax\n", -STACK_SPACE );  /* get addr of context struct */
843     output( "\tmovl %%eax,(%%edi)\n" );    /* and pass it as extra arg */
844     output( "\tmovl %%esi,%d(%%ebp)\n", 0xc4 /* Esp */ - STACK_SPACE );
845
846     /* Call the entry point */
847
848     output( "\tmovl 4(%%ebp),%%eax\n" );   /* get relay code addr */
849     output( "\taddl 12(%%ebp),%%eax\n" );
850     output( "\tcall *%%eax\n" );
851     output( "\tleal -%d(%%ebp),%%ecx\n", STACK_SPACE );
852
853     /* Restore the context structure */
854
855     output( "2:\tpushl 0x94(%%ecx)\n");     /* SegEs */
856     output( "\tpopl %%es\n" );
857     output( "\tpushl 0x90(%%ecx)\n");       /* SegFs */
858     output( "\tpopl %%fs\n" );
859     output( "\tpushl 0x8c(%%ecx)\n");       /* SegGs */
860     output( "\tpopl %%gs\n" );
861
862     output( "\tmovl 0x9c(%%ecx),%%edi\n");  /* Edi */
863     output( "\tmovl 0xa0(%%ecx),%%esi\n");  /* Esi */
864     output( "\tmovl 0xa8(%%ecx),%%edx\n");  /* Edx */
865     output( "\tmovl 0xa4(%%ecx),%%ebx\n");  /* Ebx */
866     output( "\tmovl 0xb0(%%ecx),%%eax\n");  /* Eax */
867     output( "\tmovl 0xb4(%%ecx),%%ebp\n");  /* Ebp */
868
869     output( "\tpushl 0xc8(%%ecx)\n");       /* SegSs */
870     output( "\tpopl %%ss\n" );
871     output( "\tmovl 0xc4(%%ecx),%%esp\n");  /* Esp */
872
873     output( "\tpushl 0xc0(%%ecx)\n");       /* EFlags */
874     output( "\tpushl 0xbc(%%ecx)\n");       /* SegCs */
875     output( "\tpushl 0xb8(%%ecx)\n");       /* Eip */
876     output( "\tpushl 0x98(%%ecx)\n");       /* SegDs */
877     output( "\tmovl 0xac(%%ecx),%%ecx\n");  /* Ecx */
878
879     output( "\tpopl %%ds\n" );
880     output( "\tiret\n" );
881     output_cfi( ".cfi_endproc" );
882     output_function_size( "__wine_call_from_regs" );
883
884     function_header( "__wine_restore_regs" );
885     output_cfi( ".cfi_startproc" );
886     output( "\tmovl 4(%%esp),%%ecx\n" );
887     output( "\tjmp 2b\n" );
888     output_cfi( ".cfi_endproc" );
889     output_function_size( "__wine_restore_regs" );
890 }
891
892
893 /*******************************************************************
894  *         BuildPendingEventCheck
895  *
896  * Build a function that checks whether there are any
897  * pending DPMI events.
898  *
899  * Stack layout:
900  *   
901  * (sp+12) long   eflags
902  * (sp+6)  long   cs
903  * (sp+2)  long   ip
904  * (sp)    word   fs
905  *
906  * On entry to function, fs register points to a valid TEB.
907  * On exit from function, stack will be popped.
908  */
909 static void BuildPendingEventCheck(void)
910 {
911     /* Function header */
912
913     function_header( "DPMI_PendingEventCheck" );
914
915     /* Check for pending events. */
916
917     output( "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n", VM86_PENDING_OFFSET );
918     output( "\tje %s\n", asm_name("DPMI_PendingEventCheck_Cleanup") );
919     output( "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n", DPMI_VIF_OFFSET );
920     output( "\tje %s\n", asm_name("DPMI_PendingEventCheck_Cleanup") );
921
922     /* Process pending events. */
923
924     output( "\tsti\n" );
925
926     /* Start cleanup. Restore fs register. */
927
928     output( "%s\n", asm_globl("DPMI_PendingEventCheck_Cleanup") );
929     output( "\tpopw %%fs\n" );
930
931     /* Return from function. */
932
933     output( "%s\n", asm_globl("DPMI_PendingEventCheck_Return") );
934     output( "\tiret\n" );
935
936     output_function_size( "DPMI_PendingEventCheck" );
937 }
938
939
940 /*******************************************************************
941  *         output_asm_relays16
942  *
943  * Build all the 16-bit relay callbacks
944  */
945 void output_asm_relays16(void)
946 {
947     /* File header */
948
949     output( "\t.text\n" );
950     output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") );
951
952     output( "%s\n", asm_globl("__wine_call16_start") );
953
954     /* Standard CallFrom16 routine */
955     BuildCallFrom16Core( 0, 0 );
956
957     /* Register CallFrom16 routine */
958     BuildCallFrom16Core( 1, 0 );
959
960     /* C16ThkSL CallFrom16 routine */
961     BuildCallFrom16Core( 0, 1 );
962
963     /* Standard CallTo16 routine */
964     BuildCallTo16Core( 0 );
965
966     /* Register CallTo16 routine */
967     BuildCallTo16Core( 1 );
968
969     /* Standard CallTo16 return stub */
970     BuildRet16Func();
971
972     /* CBClientThunkSL routine */
973     BuildCallTo32CBClient( 0 );
974
975     /* CBClientThunkSLEx routine */
976     BuildCallTo32CBClient( 1  );
977
978     /* Pending DPMI events check stub */
979     BuildPendingEventCheck();
980
981     output( "%s\n", asm_globl("__wine_call16_end") );
982     output_function_size( "__wine_spec_thunk_text_16" );
983
984     /* Declare the return address and data selector variables */
985     output( "\n\t.data\n\t.align %d\n", get_alignment(4) );
986     output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") );
987     output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") );
988
989     output( "\t.text\n" );
990     output( "%s:\n", asm_name("__wine_spec_thunk_text_32") );
991     build_call_from_regs_x86();
992     output_function_size( "__wine_spec_thunk_text_32" );
993 }
994
995
996 /*******************************************************************
997  *         output_asm_relays
998  *
999  * Build all the assembly relay callbacks
1000  */
1001 void output_asm_relays(void)
1002 {
1003     switch (target_cpu)
1004     {
1005     case CPU_x86:
1006         build_call_from_regs_x86();
1007         break;
1008     default:
1009         break;
1010     }
1011 }