include: Add d3dx9mesh.h X template extensions.
[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         return;
228     }
229
230
231     /* Build register CONTEXT */
232     if ( reg_func )
233     {
234         output( "\tsubl $0x2cc,%%esp\n" );       /* sizeof(CONTEXT86) */
235
236         output( "\tmovl %%ecx,0xc0(%%esp)\n" );  /* EFlags */
237
238         output( "\tmovl %%eax,0xb0(%%esp)\n" );  /* Eax */
239         output( "\tmovl %%ebx,0xa4(%%esp)\n" );  /* Ebx */
240         output( "\tmovl %%esi,0xa0(%%esp)\n" );  /* Esi */
241         output( "\tmovl %%edi,0x9c(%%esp)\n" );  /* Edi */
242
243         output( "\tmovl 0x0c(%%edx),%%eax\n");   /* FIELD_OFFSET(STACK16FRAME,ebp) */
244         output( "\tmovl %%eax,0xb4(%%esp)\n" );  /* Ebp */
245         output( "\tmovl 0x08(%%edx),%%eax\n");   /* FIELD_OFFSET(STACK16FRAME,ecx) */
246         output( "\tmovl %%eax,0xac(%%esp)\n" );  /* Ecx */
247         output( "\tmovl 0x04(%%edx),%%eax\n");   /* FIELD_OFFSET(STACK16FRAME,edx) */
248         output( "\tmovl %%eax,0xa8(%%esp)\n" );  /* Edx */
249
250         output( "\tmovzwl 0x10(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ds) */
251         output( "\tmovl %%eax,0x98(%%esp)\n" );  /* SegDs */
252         output( "\tmovzwl 0x12(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,es) */
253         output( "\tmovl %%eax,0x94(%%esp)\n" );  /* SegEs */
254         output( "\tmovzwl 0x14(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,fs) */
255         output( "\tmovl %%eax,0x90(%%esp)\n" );  /* SegFs */
256         output( "\tmovzwl 0x16(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,gs) */
257         output( "\tmovl %%eax,0x8c(%%esp)\n" );  /* SegGs */
258
259         output( "\tmovzwl 0x2e(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,cs) */
260         output( "\tmovl %%eax,0xbc(%%esp)\n" );  /* SegCs */
261         output( "\tmovzwl 0x2c(%%edx),%%eax\n"); /* FIELD_OFFSET(STACK16FRAME,ip) */
262         output( "\tmovl %%eax,0xb8(%%esp)\n" );  /* Eip */
263
264         output( "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET+2 );
265         output( "\tmovl %%eax,0xc8(%%esp)\n" );  /* SegSs */
266         output( "\t.byte 0x64\n\tmovzwl (%d), %%eax\n", STACKOFFSET );
267         output( "\taddl $0x2c,%%eax\n");         /* FIELD_OFFSET(STACK16FRAME,ip) */
268         output( "\tmovl %%eax,0xc4(%%esp)\n" );  /* Esp */
269 #if 0
270         output( "\tfsave 0x1c(%%esp)\n" ); /* FloatSave */
271 #endif
272
273         /* Push address of CONTEXT86 structure -- popped by the relay routine */
274         output( "\tmovl %%esp,%%eax\n" );
275         output( "\tandl $~15,%%esp\n" );
276         output( "\tsubl $4,%%esp\n" );
277         output( "\tpushl %%eax\n" );
278     }
279     else
280     {
281         output( "\tsubl $8,%%esp\n" );
282         output( "\tandl $~15,%%esp\n" );
283         output( "\taddl $8,%%esp\n" );
284     }
285
286     /* Call relay routine (which will call the API entry point) */
287     output( "\tleal 0x30(%%edx),%%eax\n" ); /* sizeof(STACK16FRAME) */
288     output( "\tpushl %%eax\n" );
289     output( "\tpushl 0x26(%%edx)\n");  /* FIELD_OFFSET(STACK16FRAME,entry_point) */
290     output( "\tcall *0x20(%%edx)\n");  /* FIELD_OFFSET(STACK16FRAME,relay) */
291
292     if ( reg_func )
293     {
294         output( "\tleal -748(%%ebp),%%ebx\n" ); /* sizeof(CONTEXT) + FIELD_OFFSET(STACK32FRAME,ebp) */
295
296         /* Switch stack back */
297         output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
298         output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
299         output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
300
301         /* Get return address to CallFrom16 stub */
302         output( "\taddw $0x14,%%sp\n" ); /* FIELD_OFFSET(STACK16FRAME,callfrom_ip)-4 */
303         output( "\tpopl %%eax\n" );
304         output( "\tpopl %%edx\n" );
305
306         /* Restore all registers from CONTEXT */
307         output( "\tmovw 0xc8(%%ebx),%%ss\n");   /* SegSs */
308         output( "\tmovl 0xc4(%%ebx),%%esp\n");  /* Esp */
309         output( "\taddl $4, %%esp\n" );  /* room for final return address */
310
311         output( "\tpushw 0xbc(%%ebx)\n");  /* SegCs */
312         output( "\tpushw 0xb8(%%ebx)\n");  /* Eip */
313         output( "\tpushl %%edx\n" );
314         output( "\tpushl %%eax\n" );
315         output( "\tpushl 0xc0(%%ebx)\n");  /* EFlags */
316         output( "\tpushl 0x98(%%ebx)\n");  /* SegDs */
317
318         output( "\tpushl 0x94(%%ebx)\n");  /* SegEs */
319         output( "\tpopl %%es\n" );
320         output( "\tpushl 0x90(%%ebx)\n");  /* SegFs */
321         output( "\tpopl %%fs\n" );
322         output( "\tpushl 0x8c(%%ebx)\n");  /* SegGs */
323         output( "\tpopl %%gs\n" );
324
325         output( "\tmovl 0xb4(%%ebx),%%ebp\n");  /* Ebp */
326         output( "\tmovl 0xa0(%%ebx),%%esi\n");  /* Esi */
327         output( "\tmovl 0x9c(%%ebx),%%edi\n");  /* Edi */
328         output( "\tmovl 0xb0(%%ebx),%%eax\n");  /* Eax */
329         output( "\tmovl 0xa8(%%ebx),%%edx\n");  /* Edx */
330         output( "\tmovl 0xac(%%ebx),%%ecx\n");  /* Ecx */
331         output( "\tmovl 0xa4(%%ebx),%%ebx\n");  /* Ebx */
332
333         output( "\tpopl %%ds\n" );
334         output( "\tpopfl\n" );
335         output( "\tlret\n" );
336     }
337     else
338     {
339         /* Switch stack back */
340         output( "\t.byte 0x64\n\tmovw (%d), %%ss\n", STACKOFFSET+2 );
341         output( "\t.byte 0x64\n\tmovzwl (%d), %%esp\n", STACKOFFSET );
342         output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
343
344         /* Restore registers */
345         output( "\tpopl %%edx\n" );
346         output( "\tpopl %%ecx\n" );
347         output( "\tpopl %%ebp\n" );
348         output( "\tpopw %%ds\n" );
349         output( "\tpopw %%es\n" );
350         output( "\tpopw %%fs\n" );
351         output( "\tpopw %%gs\n" );
352
353         /* Return to return stub which will return to caller */
354         output( "\tlret $12\n" );
355     }
356     if (thunk) output_function_size( "__wine_call_from_16_thunk" );
357     else if (reg_func) output_function_size( "__wine_call_from_16_regs" );
358     else output_function_size( "__wine_call_from_16" );
359 }
360
361
362 /*******************************************************************
363  *         BuildCallTo16Core
364  *
365  * This routine builds the core routines used in 32->16 thunks:
366  *
367  * extern DWORD WINAPI wine_call_to_16( FARPROC16 target, DWORD cbArgs, PEXCEPTION_HANDLER handler );
368  * extern void WINAPI wine_call_to_16_regs( CONTEXT86 *context, DWORD cbArgs, PEXCEPTION_HANDLER handler );
369  *
370  * These routines can be called directly from 32-bit code.
371  *
372  * All routines expect that the 16-bit stack contents (arguments) and the
373  * return address (segptr to CallTo16_Ret) were already set up by the
374  * caller; nb_args must contain the number of bytes to be conserved.  The
375  * 16-bit SS:SP will be set accordingly.
376  *
377  * All other registers are either taken from the CONTEXT86 structure
378  * or else set to default values.  The target routine address is either
379  * given directly or taken from the CONTEXT86.
380  */
381 static void BuildCallTo16Core( int reg_func )
382 {
383     const char *name = reg_func ? "wine_call_to_16_regs" : "wine_call_to_16";
384
385     /* Function header */
386     function_header( name );
387
388     /* Function entry sequence */
389     output_cfi( ".cfi_startproc" );
390     output( "\tpushl %%ebp\n" );
391     output_cfi( ".cfi_adjust_cfa_offset 4" );
392     output_cfi( ".cfi_rel_offset %%ebp,0" );
393     output( "\tmovl %%esp, %%ebp\n" );
394     output_cfi( ".cfi_def_cfa_register %%ebp" );
395
396     /* Save the 32-bit registers */
397     output( "\tpushl %%ebx\n" );
398     output_cfi( ".cfi_rel_offset %%ebx,-4" );
399     output( "\tpushl %%esi\n" );
400     output_cfi( ".cfi_rel_offset %%esi,-8" );
401     output( "\tpushl %%edi\n" );
402     output_cfi( ".cfi_rel_offset %%edi,-12" );
403     output( "\t.byte 0x64\n\tmov %%gs,(%d)\n", GS_OFFSET );
404
405     /* Setup exception frame */
406     output( "\t.byte 0x64\n\tpushl (%d)\n", STACKOFFSET );
407     output( "\tpushl 16(%%ebp)\n" ); /* handler */
408     output( "\t.byte 0x64\n\tpushl (0)\n" );
409     output( "\t.byte 0x64\n\tmovl %%esp,(0)\n" );
410
411     /* Call the actual CallTo16 routine (simulate a lcall) */
412     output( "\tpushl %%cs\n" );
413     output( "\tcall .L%s\n", name );
414
415     /* Remove exception frame */
416     output( "\t.byte 0x64\n\tpopl (0)\n" );
417     output( "\taddl $4, %%esp\n" );
418     output( "\t.byte 0x64\n\tpopl (%d)\n", STACKOFFSET );
419
420     if ( !reg_func )
421     {
422         /* Convert return value */
423         output( "\tandl $0xffff,%%eax\n" );
424         output( "\tshll $16,%%edx\n" );
425         output( "\torl %%edx,%%eax\n" );
426     }
427     else
428     {
429         /*
430          * Modify CONTEXT86 structure to contain new values
431          *
432          * NOTE:  We restore only EAX, EBX, EDX, EDX, EBP, and ESP.
433          *        The segment registers as well as ESI and EDI should
434          *        not be modified by a well-behaved 16-bit routine in
435          *        any case.  [If necessary, we could restore them as well,
436          *        at the cost of a somewhat less efficient return path.]
437          */
438
439         output( "\tmovl 0x14(%%esp),%%edi\n" ); /* FIELD_OFFSET(STACK32FRAME,target) - FIELD_OFFSET(STACK32FRAME,edi) */
440                 /* everything above edi has been popped already */
441
442         output( "\tmovl %%eax,0xb0(%%edi)\n");  /* Eax */
443         output( "\tmovl %%ebx,0xa4(%%edi)\n");  /* Ebx */
444         output( "\tmovl %%ecx,0xac(%%edi)\n");  /* Ecx */
445         output( "\tmovl %%edx,0xa8(%%edi)\n");  /* Edx */
446         output( "\tmovl %%ebp,0xb4(%%edi)\n");  /* Ebp */
447         output( "\tmovl %%esi,0xc4(%%edi)\n");  /* Esp */
448                  /* The return glue code saved %esp into %esi */
449     }
450
451     /* Restore the 32-bit registers */
452     output( "\tpopl %%edi\n" );
453     output_cfi( ".cfi_same_value %%edi" );
454     output( "\tpopl %%esi\n" );
455     output_cfi( ".cfi_same_value %%esi" );
456     output( "\tpopl %%ebx\n" );
457     output_cfi( ".cfi_same_value %%ebx" );
458
459     /* Function exit sequence */
460     output( "\tpopl %%ebp\n" );
461     output_cfi( ".cfi_def_cfa %%esp,4" );
462     output_cfi( ".cfi_same_value %%ebp" );
463     output( "\tret $12\n" );
464     output_cfi( ".cfi_endproc" );
465
466
467     /* Start of the actual CallTo16 routine */
468
469     output( ".L%s:\n", name );
470
471     /* Switch to the 16-bit stack */
472     output( "\tmovl %%esp,%%edx\n" );
473     output( "\t.byte 0x64\n\tmovw (%d),%%ss\n", STACKOFFSET + 2);
474     output( "\t.byte 0x64\n\tmovw (%d),%%sp\n", STACKOFFSET );
475     output( "\t.byte 0x64\n\tmovl %%edx,(%d)\n", STACKOFFSET );
476
477     /* Make %bp point to the previous stackframe (built by CallFrom16) */
478     output( "\tmovzwl %%sp,%%ebp\n" );
479     output( "\tleal 0x2a(%%ebp),%%ebp\n");  /* FIELD_OFFSET(STACK16FRAME,bp) */
480
481     /* Add the specified offset to the new sp */
482     output( "\tsubw 0x2c(%%edx), %%sp\n");  /* FIELD_OFFSET(STACK32FRAME,nb_args) */
483
484     if (reg_func)
485     {
486         /* Push the called routine address */
487         output( "\tmovl 0x28(%%edx),%%edx\n");  /* FIELD_OFFSET(STACK32FRAME,target) */
488         output( "\tpushw 0xbc(%%edx)\n");  /* SegCs */
489         output( "\tpushw 0xb8(%%edx)\n");  /* Eip */
490
491         /* Get the registers */
492         output( "\tpushw 0x98(%%edx)\n");  /* SegDs */
493         output( "\tpushl 0x94(%%edx)\n");  /* SegEs */
494         output( "\tpopl %%es\n" );
495         output( "\tpushl 0x90(%%edx)\n");  /* SegFs */
496         output( "\tpopl %%fs\n" );
497         output( "\tpushl 0x8c(%%edx)\n");  /* SegGs */
498         output( "\tpopl %%gs\n" );
499         output( "\tmovl 0xb4(%%edx),%%ebp\n");  /* Ebp */
500         output( "\tmovl 0xa0(%%edx),%%esi\n");  /* Esi */
501         output( "\tmovl 0x9c(%%edx),%%edi\n");  /* Edi */
502         output( "\tmovl 0xb0(%%edx),%%eax\n");  /* Eax */
503         output( "\tmovl 0xa4(%%edx),%%ebx\n");  /* Ebx */
504         output( "\tmovl 0xac(%%edx),%%ecx\n");  /* Ecx */
505         output( "\tmovl 0xa8(%%edx),%%edx\n");  /* Edx */
506
507         /* Get the 16-bit ds */
508         output( "\tpopw %%ds\n" );
509     }
510     else  /* not a register function */
511     {
512         /* Push the called routine address */
513         output( "\tpushl 0x28(%%edx)\n"); /* FIELD_OFFSET(STACK32FRAME,target) */
514
515         /* Set %fs and %gs to the value saved by the last CallFrom16 */
516         output( "\tpushw -22(%%ebp)\n" ); /* FIELD_OFFSET(STACK16FRAME,fs)-FIELD_OFFSET(STACK16FRAME,bp) */
517         output( "\tpopw %%fs\n" );
518         output( "\tpushw -20(%%ebp)\n" ); /* FIELD_OFFSET(STACK16FRAME,gs)-FIELD_OFFSET(STACK16FRAME,bp) */
519         output( "\tpopw %%gs\n" );
520
521         /* Set %ds and %es (and %ax just in case) equal to %ss */
522         output( "\tmovw %%ss,%%ax\n" );
523         output( "\tmovw %%ax,%%ds\n" );
524         output( "\tmovw %%ax,%%es\n" );
525     }
526
527     /* Jump to the called routine */
528     output( "\t.byte 0x66\n" );
529     output( "\tlret\n" );
530
531     /* Function footer */
532     output_function_size( name );
533 }
534
535
536 /*******************************************************************
537  *         BuildRet16Func
538  *
539  * Build the return code for 16-bit callbacks
540  */
541 static void BuildRet16Func(void)
542 {
543     function_header( "__wine_call_to_16_ret" );
544
545     /* Save %esp into %esi */
546     output( "\tmovl %%esp,%%esi\n" );
547
548     /* Restore 32-bit segment registers */
549
550     output( "\t.byte 0x2e\n\tmovl %s", asm_name("CallTo16_DataSelector") );
551     output( "-%s,%%edi\n", asm_name("__wine_call16_start") );
552     output( "\tmovw %%di,%%ds\n" );
553     output( "\tmovw %%di,%%es\n" );
554
555     output( "\t.byte 0x2e\n\tmov %s", asm_name("CallTo16_TebSelector") );
556     output( "-%s,%%fs\n", asm_name("__wine_call16_start") );
557
558     output( "\t.byte 0x64\n\tmov (%d),%%gs\n", GS_OFFSET );
559
560     /* Restore the 32-bit stack */
561
562     output( "\tmovw %%di,%%ss\n" );
563     output( "\t.byte 0x64\n\tmovl (%d),%%esp\n", STACKOFFSET );
564
565     /* Return to caller */
566
567     output( "\tlret\n" );
568     output_function_size( "__wine_call_to_16_ret" );
569 }
570
571
572 /*******************************************************************
573  *         BuildCallTo32CBClient
574  *
575  * Call a CBClient relay stub from 32-bit code (KERNEL.620).
576  *
577  * Since the relay stub is itself 32-bit, this should not be a problem;
578  * unfortunately, the relay stubs are expected to switch back to a
579  * 16-bit stack (and 16-bit code) after completion :-(
580  *
581  * This would conflict with our 16- vs. 32-bit stack handling, so
582  * we simply switch *back* to our 32-bit stack before returning to
583  * the caller ...
584  *
585  * The CBClient relay stub expects to be called with the following
586  * 16-bit stack layout, and with ebp and ebx pointing into the 16-bit
587  * stack at the designated places:
588  *
589  *    ...
590  *  (ebp+14) original arguments to the callback routine
591  *  (ebp+10) far return address to original caller
592  *  (ebp+6)  Thunklet target address
593  *  (ebp+2)  Thunklet relay ID code
594  *  (ebp)    BP (saved by CBClientGlueSL)
595  *  (ebp-2)  SI (saved by CBClientGlueSL)
596  *  (ebp-4)  DI (saved by CBClientGlueSL)
597  *  (ebp-6)  DS (saved by CBClientGlueSL)
598  *
599  *   ...     buffer space used by the 16-bit side glue for temp copies
600  *
601  *  (ebx+4)  far return address to 16-bit side glue code
602  *  (ebx)    saved 16-bit ss:sp (pointing to ebx+4)
603  *
604  * The 32-bit side glue code accesses both the original arguments (via ebp)
605  * and the temporary copies prepared by the 16-bit side glue (via ebx).
606  * After completion, the stub will load ss:sp from the buffer at ebx
607  * and perform a far return to 16-bit code.
608  *
609  * To trick the relay stub into returning to us, we replace the 16-bit
610  * return address to the glue code by a cs:ip pair pointing to our
611  * return entry point (the original return address is saved first).
612  * Our return stub thus called will then reload the 32-bit ss:esp and
613  * return to 32-bit code (by using and ss:esp value that we have also
614  * pushed onto the 16-bit stack before and a cs:eip values found at
615  * that position on the 32-bit stack).  The ss:esp to be restored is
616  * found relative to the 16-bit stack pointer at:
617  *
618  *  (ebx-4)   ss  (flat)
619  *  (ebx-8)   sp  (32-bit stack pointer)
620  *
621  * The second variant of this routine, CALL32_CBClientEx, which is used
622  * to implement KERNEL.621, has to cope with yet another problem: Here,
623  * the 32-bit side directly returns to the caller of the CBClient thunklet,
624  * restoring registers saved by CBClientGlueSL and cleaning up the stack.
625  * As we have to return to our 32-bit code first, we have to adapt the
626  * layout of our temporary area so as to include values for the registers
627  * that are to be restored, and later (in the implementation of KERNEL.621)
628  * we *really* restore them. The return stub restores DS, DI, SI, and BP
629  * from the stack, skips the next 8 bytes (CBClient relay code / target),
630  * and then performs a lret NN, where NN is the number of arguments to be
631  * removed. Thus, we prepare our temporary area as follows:
632  *
633  *     (ebx+22) 16-bit cs  (this segment)
634  *     (ebx+20) 16-bit ip  ('16-bit' return entry point)
635  *     (ebx+16) 32-bit ss  (flat)
636  *     (ebx+12) 32-bit sp  (32-bit stack pointer)
637  *     (ebx+10) 16-bit bp  (points to ebx+24)
638  *     (ebx+8)  16-bit si  (ignored)
639  *     (ebx+6)  16-bit di  (ignored)
640  *     (ebx+4)  16-bit ds  (we actually use the flat DS here)
641  *     (ebx+2)  16-bit ss  (16-bit stack segment)
642  *     (ebx+0)  16-bit sp  (points to ebx+4)
643  *
644  * Note that we ensure that DS is not changed and remains the flat segment,
645  * and the 32-bit stack pointer our own return stub needs fits just
646  * perfectly into the 8 bytes that are skipped by the Windows stub.
647  * One problem is that we have to determine the number of removed arguments,
648  * as these have to be really removed in KERNEL.621. Thus, the BP value
649  * that we place in the temporary area to be restored, contains the value
650  * that SP would have if no arguments were removed. By comparing the actual
651  * value of SP with this value in our return stub we can compute the number
652  * of removed arguments. This is then returned to KERNEL.621.
653  *
654  * The stack layout of this function:
655  * (ebp+20)  nArgs     pointer to variable receiving nr. of args (Ex only)
656  * (ebp+16)  esi       pointer to caller's esi value
657  * (ebp+12)  arg       ebp value to be set for relay stub
658  * (ebp+8)   func      CBClient relay stub address
659  * (ebp+4)   ret addr
660  * (ebp)     ebp
661  */
662 static void BuildCallTo32CBClient( int isEx )
663 {
664     function_header( isEx ? "CALL32_CBClientEx" : "CALL32_CBClient" );
665
666     /* Entry code */
667
668     output_cfi( ".cfi_startproc" );
669     output( "\tpushl %%ebp\n" );
670     output_cfi( ".cfi_adjust_cfa_offset 4" );
671     output_cfi( ".cfi_rel_offset %%ebp,0" );
672     output( "\tmovl %%esp,%%ebp\n" );
673     output_cfi( ".cfi_def_cfa_register %%ebp" );
674     output( "\tpushl %%edi\n" );
675     output_cfi( ".cfi_rel_offset %%edi,-4" );
676     output( "\tpushl %%esi\n" );
677     output_cfi( ".cfi_rel_offset %%esi,-8" );
678     output( "\tpushl %%ebx\n" );
679     output_cfi( ".cfi_rel_offset %%ebx,-12" );
680
681     /* Get pointer to temporary area and save the 32-bit stack pointer */
682
683     output( "\tmovl 16(%%ebp), %%ebx\n" );
684     output( "\tleal -8(%%esp), %%eax\n" );
685
686     if ( !isEx )
687         output( "\tmovl %%eax, -8(%%ebx)\n" );
688     else
689         output( "\tmovl %%eax, 12(%%ebx)\n" );
690
691     /* Set up registers and call CBClient relay stub (simulating a far call) */
692
693     output( "\tmovl 20(%%ebp), %%esi\n" );
694     output( "\tmovl (%%esi), %%esi\n" );
695
696     output( "\tmovl 8(%%ebp), %%eax\n" );
697     output( "\tmovl 12(%%ebp), %%ebp\n" );
698
699     output( "\tpushl %%cs\n" );
700     output( "\tcall *%%eax\n" );
701
702     /* Return new esi value to caller */
703
704     output( "\tmovl 32(%%esp), %%edi\n" );
705     output( "\tmovl %%esi, (%%edi)\n" );
706
707     /* Return argument size to caller */
708     if ( isEx )
709     {
710         output( "\tmovl 36(%%esp), %%ebx\n" );
711         output( "\tmovl %%ebp, (%%ebx)\n" );
712     }
713
714     /* Restore registers and return */
715
716     output( "\tpopl %%ebx\n" );
717     output_cfi( ".cfi_same_value %%ebx" );
718     output( "\tpopl %%esi\n" );
719     output_cfi( ".cfi_same_value %%esi" );
720     output( "\tpopl %%edi\n" );
721     output_cfi( ".cfi_same_value %%edi" );
722     output( "\tpopl %%ebp\n" );
723     output_cfi( ".cfi_def_cfa %%esp,4" );
724     output_cfi( ".cfi_same_value %%ebp" );
725     output( "\tret\n" );
726     output_cfi( ".cfi_endproc" );
727     output_function_size( isEx ? "CALL32_CBClientEx" : "CALL32_CBClient" );
728
729     /* '16-bit' return stub */
730
731     function_header( isEx ? "CALL32_CBClientEx_Ret" : "CALL32_CBClient_Ret" );
732     if ( !isEx )
733     {
734         output( "\tmovzwl %%sp, %%ebx\n" );
735         output( "\tlssl %%ss:-16(%%ebx), %%esp\n" );
736     }
737     else
738     {
739         output( "\tmovzwl %%bp, %%ebx\n" );
740         output( "\tsubw %%bp, %%sp\n" );
741         output( "\tmovzwl %%sp, %%ebp\n" );
742         output( "\tlssl %%ss:-12(%%ebx), %%esp\n" );
743     }
744     output( "\tlret\n" );
745     output_function_size( isEx ? "CALL32_CBClientEx_Ret" : "CALL32_CBClient_Ret" );
746 }
747
748
749 /*******************************************************************
750  *         build_call_from_regs_x86
751  *
752  * Build a 32-bit-to-Wine call-back function for a 'register' function.
753  * 'args' is the number of dword arguments.
754  *
755  * Stack layout:
756  *   ...
757  * (ebp+20)  first arg
758  * (ebp+16)  ret addr to user code
759  * (ebp+12)  func to call (relative to relay code ret addr)
760  * (ebp+8)   number of args
761  * (ebp+4)   ret addr to relay code
762  * (ebp+0)   saved ebp
763  * (ebp-128) buffer area to allow stack frame manipulation
764  * (ebp-332) CONTEXT86 struct
765  * (ebp-336) padding for stack alignment
766  * (ebp-336-n) CONTEXT86 *argument
767  *  ....     other arguments copied from (ebp+12)
768  *
769  * The entry point routine is called with a CONTEXT* extra argument,
770  * following the normal args. In this context structure, EIP_reg
771  * contains the return address to user code, and ESP_reg the stack
772  * pointer on return (with the return address and arguments already
773  * removed).
774  */
775 static void build_call_from_regs_x86(void)
776 {
777     static const int STACK_SPACE = 128 + 0x2cc /* sizeof(CONTEXT86) */;
778
779     /* Function header */
780
781     output( "\t.text\n" );
782     function_header( "__wine_call_from_regs" );
783
784     /* Allocate some buffer space on the stack */
785
786     output_cfi( ".cfi_startproc" );
787     output( "\tpushl %%ebp\n" );
788     output_cfi( ".cfi_adjust_cfa_offset 4" );
789     output_cfi( ".cfi_rel_offset %%ebp,0" );
790     output( "\tmovl %%esp,%%ebp\n" );
791     output_cfi( ".cfi_def_cfa_register %%ebp" );
792     output( "\tleal -%d(%%esp),%%esp\n", STACK_SPACE );
793
794     /* Build the context structure */
795
796     output( "\tmovl %%eax,0xb0(%%esp)\n" );  /* Eax */
797     output( "\tpushfl\n" );
798     output( "\tpopl %%eax\n" );
799     output( "\tmovl %%eax,0xc0(%%esp)\n");  /* EFlags */
800     output( "\tmovl 0(%%ebp),%%eax\n" );
801     output( "\tmovl %%eax,0xb4(%%esp)\n");  /* Ebp */
802     output( "\tmovl %%ebx,0xa4(%%esp)\n");  /* Ebx */
803     output( "\tmovl %%ecx,0xac(%%esp)\n");  /* Ecx */
804     output( "\tmovl %%edx,0xa8(%%esp)\n");  /* Edx */
805     output( "\tmovl %%esi,0xa0(%%esp)\n");  /* Esi */
806     output( "\tmovl %%edi,0x9c(%%esp)\n");  /* Edi */
807
808     output( "\txorl %%eax,%%eax\n" );
809     output( "\tmovw %%cs,%%ax\n" );
810     output( "\tmovl %%eax,0xbc(%%esp)\n");  /* SegCs */
811     output( "\tmovw %%es,%%ax\n" );
812     output( "\tmovl %%eax,0x94(%%esp)\n");  /* SegEs */
813     output( "\tmovw %%fs,%%ax\n" );
814     output( "\tmovl %%eax,0x90(%%esp)\n");  /* SegFs */
815     output( "\tmovw %%gs,%%ax\n" );
816     output( "\tmovl %%eax,0x8c(%%esp)\n");  /* SegGs */
817     output( "\tmovw %%ss,%%ax\n" );
818     output( "\tmovl %%eax,0xc8(%%esp)\n");  /* SegSs */
819     output( "\tmovw %%ds,%%ax\n" );
820     output( "\tmovl %%eax,0x98(%%esp)\n");  /* SegDs */
821     output( "\tmovw %%ax,%%es\n" );  /* set %es equal to %ds just in case */
822
823     output( "\tmovl $0x10007,0(%%esp)\n");  /* ContextFlags */
824
825     output( "\tmovl 16(%%ebp),%%eax\n" ); /* Get %eip at time of call */
826     output( "\tmovl %%eax,0xb8(%%esp)\n");  /* Eip */
827
828     /* Transfer the arguments */
829
830     output( "\tmovl 8(%%ebp),%%ecx\n" );    /* fetch number of args to copy */
831     output( "\tleal 4(,%%ecx,4),%%edx\n" ); /* add 4 for context arg */
832     output( "\tsubl %%edx,%%esp\n" );
833     output( "\tandl $~15,%%esp\n" );
834     output( "\tleal 20(%%ebp),%%esi\n" );  /* get %esp at time of call */
835     output( "\tmovl %%esp,%%edi\n" );
836     output( "\ttest %%ecx,%%ecx\n" );
837     output( "\tjz 1f\n" );
838     output( "\tcld\n" );
839     output( "\trep\n\tmovsl\n" );  /* copy args */
840     output( "1:\tleal %d(%%ebp),%%eax\n", -STACK_SPACE );  /* get addr of context struct */
841     output( "\tmovl %%eax,(%%edi)\n" );    /* and pass it as extra arg */
842     output( "\tmovl %%esi,%d(%%ebp)\n", 0xc4 /* Esp */ - STACK_SPACE );
843
844     /* Call the entry point */
845
846     output( "\tmovl 4(%%ebp),%%eax\n" );   /* get relay code addr */
847     output( "\taddl 12(%%ebp),%%eax\n" );
848     output( "\tcall *%%eax\n" );
849     output( "\tleal -%d(%%ebp),%%ecx\n", STACK_SPACE );
850
851     /* Restore the context structure */
852
853     output( "2:\tpushl 0x94(%%ecx)\n");     /* SegEs */
854     output( "\tpopl %%es\n" );
855     output( "\tpushl 0x90(%%ecx)\n");       /* SegFs */
856     output( "\tpopl %%fs\n" );
857     output( "\tpushl 0x8c(%%ecx)\n");       /* SegGs */
858     output( "\tpopl %%gs\n" );
859
860     output( "\tmovl 0x9c(%%ecx),%%edi\n");  /* Edi */
861     output( "\tmovl 0xa0(%%ecx),%%esi\n");  /* Esi */
862     output( "\tmovl 0xa8(%%ecx),%%edx\n");  /* Edx */
863     output( "\tmovl 0xa4(%%ecx),%%ebx\n");  /* Ebx */
864     output( "\tmovl 0xb0(%%ecx),%%eax\n");  /* Eax */
865     output( "\tmovl 0xb4(%%ecx),%%ebp\n");  /* Ebp */
866
867     output( "\tpushl 0xc8(%%ecx)\n");       /* SegSs */
868     output( "\tpopl %%ss\n" );
869     output( "\tmovl 0xc4(%%ecx),%%esp\n");  /* Esp */
870
871     output( "\tpushl 0xc0(%%ecx)\n");       /* EFlags */
872     output( "\tpushl 0xbc(%%ecx)\n");       /* SegCs */
873     output( "\tpushl 0xb8(%%ecx)\n");       /* Eip */
874     output( "\tpushl 0x98(%%ecx)\n");       /* SegDs */
875     output( "\tmovl 0xac(%%ecx),%%ecx\n");  /* Ecx */
876
877     output( "\tpopl %%ds\n" );
878     output( "\tiret\n" );
879     output_cfi( ".cfi_endproc" );
880     output_function_size( "__wine_call_from_regs" );
881
882     function_header( "__wine_restore_regs" );
883     output_cfi( ".cfi_startproc" );
884     output( "\tmovl 4(%%esp),%%ecx\n" );
885     output( "\tjmp 2b\n" );
886     output_cfi( ".cfi_endproc" );
887     output_function_size( "__wine_restore_regs" );
888 }
889
890
891 /*******************************************************************
892  *         BuildPendingEventCheck
893  *
894  * Build a function that checks whether there are any
895  * pending DPMI events.
896  *
897  * Stack layout:
898  *   
899  * (sp+12) long   eflags
900  * (sp+6)  long   cs
901  * (sp+2)  long   ip
902  * (sp)    word   fs
903  *
904  * On entry to function, fs register points to a valid TEB.
905  * On exit from function, stack will be popped.
906  */
907 static void BuildPendingEventCheck(void)
908 {
909     /* Function header */
910
911     function_header( "DPMI_PendingEventCheck" );
912
913     /* Check for pending events. */
914
915     output( "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n", VM86_PENDING_OFFSET );
916     output( "\tje %s\n", asm_name("DPMI_PendingEventCheck_Cleanup") );
917     output( "\t.byte 0x64\n\ttestl $0xffffffff,(%d)\n", DPMI_VIF_OFFSET );
918     output( "\tje %s\n", asm_name("DPMI_PendingEventCheck_Cleanup") );
919
920     /* Process pending events. */
921
922     output( "\tsti\n" );
923
924     /* Start cleanup. Restore fs register. */
925
926     output( "%s\n", asm_globl("DPMI_PendingEventCheck_Cleanup") );
927     output( "\tpopw %%fs\n" );
928
929     /* Return from function. */
930
931     output( "%s\n", asm_globl("DPMI_PendingEventCheck_Return") );
932     output( "\tiret\n" );
933
934     output_function_size( "DPMI_PendingEventCheck" );
935 }
936
937
938 /*******************************************************************
939  *         output_asm_relays16
940  *
941  * Build all the 16-bit relay callbacks
942  */
943 void output_asm_relays16(void)
944 {
945     /* File header */
946
947     output( "\t.text\n" );
948     output( "%s:\n\n", asm_name("__wine_spec_thunk_text_16") );
949
950     output( "%s\n", asm_globl("__wine_call16_start") );
951
952     /* Standard CallFrom16 routine */
953     BuildCallFrom16Core( 0, 0 );
954
955     /* Register CallFrom16 routine */
956     BuildCallFrom16Core( 1, 0 );
957
958     /* C16ThkSL CallFrom16 routine */
959     BuildCallFrom16Core( 0, 1 );
960
961     /* Standard CallTo16 routine */
962     BuildCallTo16Core( 0 );
963
964     /* Register CallTo16 routine */
965     BuildCallTo16Core( 1 );
966
967     /* Standard CallTo16 return stub */
968     BuildRet16Func();
969
970     /* CBClientThunkSL routine */
971     BuildCallTo32CBClient( 0 );
972
973     /* CBClientThunkSLEx routine */
974     BuildCallTo32CBClient( 1  );
975
976     /* Pending DPMI events check stub */
977     BuildPendingEventCheck();
978
979     output( "%s\n", asm_globl("__wine_call16_end") );
980     output_function_size( "__wine_spec_thunk_text_16" );
981
982     /* Declare the return address and data selector variables */
983     output( "\n\t.data\n\t.align %d\n", get_alignment(4) );
984     output( "%s\n\t.long 0\n", asm_globl("CallTo16_DataSelector") );
985     output( "%s\n\t.long 0\n", asm_globl("CallTo16_TebSelector") );
986
987     output( "\t.text\n" );
988     output( "%s:\n", asm_name("__wine_spec_thunk_text_32") );
989     build_call_from_regs_x86();
990     output_function_size( "__wine_spec_thunk_text_32" );
991 }
992
993
994 /*******************************************************************
995  *         output_asm_relays
996  *
997  * Build all the assembly relay callbacks
998  */
999 void output_asm_relays(void)
1000 {
1001     switch (target_cpu)
1002     {
1003     case CPU_x86:
1004         build_call_from_regs_x86();
1005         break;
1006     default:
1007         break;
1008     }
1009 }