From 96508ad686fb8c80cb678670841ff29987c72e89 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Sun, 18 Sep 2005 12:25:22 +0000 Subject: [PATCH] Moved return value handling to the individual relay thunks so that we only need one version of wine_call_from_16. Patch the wine_call_from_16 address along with the cs value directly in the 16-bit code segment to avoid the need for special magic in the import thunks. --- dlls/kernel/kernel16_private.h | 7 +++- dlls/kernel/kernel32.spec | 4 +- dlls/kernel/ne_module.c | 11 ++++- dlls/kernel/relay16.c | 51 ++++++++++-------------- dlls/winedos/relay.c | 6 ++- include/wine/winbase16.h | 8 ---- tools/winebuild/import.c | 26 +----------- tools/winebuild/relay.c | 40 ++++++------------- tools/winebuild/spec16.c | 73 ++++++++++++++++------------------ 9 files changed, 91 insertions(+), 135 deletions(-) diff --git a/dlls/kernel/kernel16_private.h b/dlls/kernel/kernel16_private.h index b758a8777ff..28b62de1375 100644 --- a/dlls/kernel/kernel16_private.h +++ b/dlls/kernel/kernel16_private.h @@ -126,8 +126,8 @@ typedef struct BYTE lcall; /* lcall __FLATCS__:glue */ void *glue; WORD flatcs; - WORD lret; /* lret $nArgs */ - WORD nArgs; + WORD ret[5]; /* return sequence */ + WORD movl; /* movl arg_types[1],arg_types[0](%esi) */ DWORD arg_types[2]; /* type of each argument */ } CALLFROM16; @@ -147,6 +147,9 @@ typedef struct _THHOOK HTASK16 LockTDB; /* 14 hLockedTask */ } THHOOK; +extern LONG __wine_call_from_16(); +extern void __wine_call_from_16_regs(); + extern THHOOK *pThhook; #include "poppack.h" diff --git a/dlls/kernel/kernel32.spec b/dlls/kernel/kernel32.spec index 3a5ea961da0..701eecd8fe0 100644 --- a/dlls/kernel/kernel32.spec +++ b/dlls/kernel/kernel32.spec @@ -1247,9 +1247,7 @@ # 16-bit relays @ cdecl __wine_dll_register_16(ptr str) @ cdecl __wine_dll_unregister_16(ptr) -@ varargs __wine_call_from_16_word() -@ varargs __wine_call_from_16_long() -@ varargs __wine_call_from_16_regs() +@ varargs -private __wine_call_from_16_regs() # Unix files @ cdecl wine_get_unix_file_name(wstr) diff --git a/dlls/kernel/ne_module.c b/dlls/kernel/ne_module.c index 299f6d962c1..58686820d7f 100644 --- a/dlls/kernel/ne_module.c +++ b/dlls/kernel/ne_module.c @@ -112,8 +112,15 @@ inline static void patch_code_segment( NE_MODULE *pModule ) call = GlobalLock16( pSeg->hSeg ); - if (call->flatcs != wine_get_cs()) /* need to patch cs values */ - for (i = 0; call[i].pushl == 0x68; i++) call[i].flatcs = wine_get_cs(); + /* patch glue code address and code selector */ + for (i = 0; call[i].pushl == 0x68; i++) + { + if (call[i].ret[0] == 0xca66 || call[i].ret[0] == 0xcb66) /* register entry point? */ + call[i].glue = __wine_call_from_16_regs; + else + call[i].glue = __wine_call_from_16; + call[i].flatcs = wine_get_cs(); + } if (TRACE_ON(relay)) /* patch relay functions to all point to relay_call_from_16 */ for (i = 0; call[i].pushl == 0x68; i++) call[i].relay = relay_call_from_16; diff --git a/dlls/kernel/relay16.c b/dlls/kernel/relay16.c index 48f8a8d42f3..ff229000461 100644 --- a/dlls/kernel/relay16.c +++ b/dlls/kernel/relay16.c @@ -277,7 +277,7 @@ static const CALLFROM16 *get_entry_point( STACK16FRAME *frame, LPSTR module, LPS /* Retrieve entry point call structure */ p = MapSL( MAKESEGPTR( frame->module_cs, frame->callfrom_ip ) ); /* p now points to lret, get the start of CALLFROM16 structure */ - return (CALLFROM16 *)(p - (BYTE *)&((CALLFROM16 *)0)->lret); + return (CALLFROM16 *)(p - (BYTE *)&((CALLFROM16 *)0)->ret); } @@ -304,10 +304,14 @@ __ASM_GLOBAL_FUNC( call_entry_point, static int relay_call_from_16_no_debug( void *entry_point, unsigned char *args16, CONTEXT86 *context, const CALLFROM16 *call ) { - int i, nb_args, args32[20]; + unsigned int i, j, nb_args = 0; + int args32[20]; - nb_args = 0; - if (call->lret == 0xcb66) /* cdecl */ + /* look for the ret instruction */ + for (j = 0; j < sizeof(call->ret)/sizeof(call->ret[0]); j++) + if (call->ret[j] == 0xca66 || call->ret[j] == 0xcb66) break; + + if (call->ret[j] == 0xcb66) /* cdecl */ { for (i = 0; i < 20; i++, nb_args++) { @@ -345,7 +349,7 @@ static int relay_call_from_16_no_debug( void *entry_point, unsigned char *args16 else /* not cdecl */ { /* Start with the last arg */ - args16 += call->nArgs; + args16 += call->ret[j + 1]; for (i = 0; i < 20; i++, nb_args++) { int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7; @@ -377,7 +381,8 @@ static int relay_call_from_16_no_debug( void *entry_point, unsigned char *args16 } } - if (call->arg_types[0] & ARG_REGISTER) args32[nb_args++] = (int)context; + if (!j) /* register function */ + args32[nb_args++] = (int)context; SYSLEVEL_CheckNotLevel( 2 ); @@ -394,7 +399,8 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con { STACK16FRAME *frame; WORD ordinal; - int i, ret_val, nb_args, args32[20]; + unsigned int i, j, nb_args = 0; + int ret_val, args32[20]; char module[10], func[64]; const CALLFROM16 *call; @@ -405,8 +411,11 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con DPRINTF( "%04lx:Call %s.%d: %s(",GetCurrentThreadId(), module, ordinal, func ); - nb_args = 0; - if (call->lret == 0xcb66) /* cdecl */ + /* look for the ret instruction */ + for (j = 0; j < sizeof(call->ret)/sizeof(call->ret[0]); j++) + if (call->ret[j] == 0xca66 || call->ret[j] == 0xcb66) break; + + if (call->ret[j] == 0xcb66) /* cdecl */ { for (i = 0; i < 20; i++, nb_args++) { @@ -460,7 +469,7 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con else /* not cdecl */ { /* Start with the last arg */ - args16 += call->nArgs; + args16 += call->ret[j + 1]; for (i = 0; i < 20; i++, nb_args++) { int type = (call->arg_types[i / 10] >> (3 * (i % 10))) & 7; @@ -513,7 +522,7 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con DPRINTF( ") ret=%04x:%04x ds=%04x\n", frame->cs, frame->ip, frame->ds ); - if (call->arg_types[0] & ARG_REGISTER) + if (!j) /* register function */ { args32[nb_args++] = (int)context; DPRINTF(" AX=%04x BX=%04x CX=%04x DX=%04x SI=%04x DI=%04x ES=%04x EFL=%08lx\n", @@ -529,7 +538,7 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con SYSLEVEL_CheckNotLevel( 2 ); DPRINTF( "%04lx:Ret %s.%d: %s() ",GetCurrentThreadId(), module, ordinal, func ); - if (call->arg_types[0] & ARG_REGISTER) + if (!j) /* register function */ { DPRINTF("retval=none ret=%04x:%04x ds=%04x\n", (WORD)context->SegCs, LOWORD(context->Eip), (WORD)context->SegDs); @@ -541,7 +550,7 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con else { frame = CURRENT_STACK16; /* might have be changed by the entry point */ - if (call->arg_types[0] & ARG_RET16) + if (j == 1) /* 16-bit return sequence */ DPRINTF( "retval=%04x ret=%04x:%04x ds=%04x\n", ret_val & 0xffff, frame->cs, frame->ip, frame->ds ); else @@ -558,22 +567,6 @@ int relay_call_from_16( void *entry_point, unsigned char *args16, CONTEXT86 *con * (these will never be called but need to be present to satisfy the linker ...) */ -/*********************************************************************** - * __wine_call_from_16_word (KERNEL32.@) - */ -WORD __wine_call_from_16_word() -{ - assert( FALSE ); -} - -/*********************************************************************** - * __wine_call_from_16_long (KERNEL32.@) - */ -LONG __wine_call_from_16_long() -{ - assert( FALSE ); -} - /*********************************************************************** * __wine_call_from_16_regs (KERNEL32.@) */ diff --git a/dlls/winedos/relay.c b/dlls/winedos/relay.c index a30d16a89ed..c881dfd4e08 100644 --- a/dlls/winedos/relay.c +++ b/dlls/winedos/relay.c @@ -167,6 +167,7 @@ void DOSVM_RelayHandler( CONTEXT86 *context ) */ void DOSVM_BuildCallFrame( CONTEXT86 *context, DOSRELAY relay, LPVOID data ) { + static void (*__wine_call_from_16_regs_ptr)(); WORD code_sel = DOSVM_dpmi_segments->relay_code_sel; /* @@ -195,6 +196,9 @@ void DOSVM_BuildCallFrame( CONTEXT86 *context, DOSRELAY relay, LPVOID data ) /* * Adjust code pointer. */ + if (!__wine_call_from_16_regs_ptr) + __wine_call_from_16_regs_ptr = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), + "__wine_call_from_16_regs" ); context->SegCs = wine_get_cs(); - context->Eip = (DWORD)__wine_call_from_16_regs; + context->Eip = (DWORD)__wine_call_from_16_regs_ptr; } diff --git a/include/wine/winbase16.h b/include/wine/winbase16.h index 7994c3b82fb..984c8db53d2 100644 --- a/include/wine/winbase16.h +++ b/include/wine/winbase16.h @@ -217,14 +217,6 @@ enum arg_types ARG_VARARG /* start of varargs */ }; -/* flags added to arg_types[0] */ -#define ARG_RET16 0x80000000 /* function returns 16-bit value */ -#define ARG_REGISTER 0x40000000 /* function is register */ - -extern WORD __wine_call_from_16_word(); -extern LONG __wine_call_from_16_long(); -extern void __wine_call_from_16_regs(); - #include #define INVALID_HANDLE_VALUE16 ((HANDLE16) -1) diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index a1a0273d6c4..61d6ef4cc2f 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -637,34 +637,12 @@ static void output_import_thunk( FILE *outfile, const char *name, const char *ta case CPU_x86: if (!UsePIC) { - if (strstr( name, "__wine_call_from_16" )) fprintf( outfile, "\t.byte 0x2e\n" ); fprintf( outfile, "\tjmp *(%s+%d)\n", table, pos ); } else { - if (!strcmp( name, "__wine_call_from_16_regs" )) - { - /* special case: need to preserve all registers */ - fprintf( outfile, "\tpushl %%eax\n" ); - fprintf( outfile, "\tpushl %%ecx\n" ); - fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); - fprintf( outfile, ".L__wine_spec_%s:\n", name ); - fprintf( outfile, "1:\t.byte 0x2e\n" ); - fprintf( outfile, "\tmovl %s+%d-1b(%%eax),%%eax\n", table, pos ); - fprintf( outfile, "\tmovzwl %%sp, %%ecx\n" ); - fprintf( outfile, "\t.byte 0x36\n" ); - fprintf( outfile, "\txchgl %%eax,4(%%ecx)\n" ); - fprintf( outfile, "\tpopl %%ecx\n" ); - fprintf( outfile, "\tret\n" ); - } - else - { - fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); - fprintf( outfile, "1:" ); - if (strstr( name, "__wine_call_from_16" )) - fprintf( outfile, "\t.byte 0x2e\n" ); - fprintf( outfile, "\tjmp *%s+%d-1b(%%eax)\n", table, pos ); - } + fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") ); + fprintf( outfile, "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos ); } break; case CPU_x86_64: diff --git a/tools/winebuild/relay.c b/tools/winebuild/relay.c index 410940fa162..ffec1cd023f 100644 --- a/tools/winebuild/relay.c +++ b/tools/winebuild/relay.c @@ -118,15 +118,12 @@ static inline const char *data16_prefix(void) * (sp-20) long saved edx * (sp-24) long saved previous stack */ -static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int short_ret ) +static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk ) { - const char *name = thunk? "thunk" : reg_func? "regs" : short_ret? "word" : "long"; - /* Function header */ if (thunk) function_header( outfile, "__wine_call_from_16_thunk" ); else if (reg_func) function_header( outfile, "__wine_call_from_16_regs" ); - else if (short_ret) function_header( outfile, "__wine_call_from_16_word" ); - else function_header( outfile, "__wine_call_from_16_long" ); + else function_header( outfile, "__wine_call_from_16" ); /* Create STACK16FRAME (except STACK32FRAME link) */ fprintf( outfile, "\tpushw %%gs\n" ); @@ -142,11 +139,10 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho if ( UsePIC ) { - fprintf( outfile, "\tcall .Lcall_from_16_%s.getpc\n", name ); - fprintf( outfile, ".Lcall_from_16_%s.getpc:\n", name ); - fprintf( outfile, "\tpopl %%ecx\n" ); - fprintf( outfile, "\t.byte 0x2e\n\tmovl %s-.Lcall_from_16_%s.getpc(%%ecx),%%edx\n", - asm_name("CallTo16_DataSelector"), name ); + fprintf( outfile, "\tcall 1f\n" ); + fprintf( outfile, "1:\tpopl %%ecx\n" ); + fprintf( outfile, "\t.byte 0x2e\n\tmovl %s-1b(%%ecx),%%edx\n", + asm_name("CallTo16_DataSelector") ); } else fprintf( outfile, "\t.byte 0x2e\n\tmovl %s,%%edx\n", asm_name("CallTo16_DataSelector") ); @@ -156,8 +152,7 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho fprintf( outfile, "%s\tmovw %%dx, %%es\n", data16_prefix() ); if ( UsePIC ) - fprintf( outfile, "\tmovw %s-.Lcall_from_16_%s.getpc(%%ecx), %%fs\n", - asm_name("CallTo16_TebSelector"), name ); + fprintf( outfile, "\tmovw %s-1b(%%ecx), %%fs\n", asm_name("CallTo16_TebSelector") ); else fprintf( outfile, "\tmovw %s, %%fs\n", asm_name("CallTo16_TebSelector") ); @@ -169,7 +164,7 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho fprintf( outfile, "\tshrl $1, %%edx\n" ); if (UsePIC) { - fprintf( outfile, "\taddl wine_ldt_copy_ptr-.Lcall_from_16_%s.getpc(%%ecx),%%edx\n", name ); + fprintf( outfile, "\taddl wine_ldt_copy_ptr-1b(%%ecx),%%edx\n" ); fprintf( outfile, "\tmovl (%%edx), %%edx\n" ); } else @@ -352,18 +347,12 @@ static void BuildCallFrom16Core( FILE *outfile, int reg_func, int thunk, int sho fprintf( outfile, "\tpopw %%fs\n" ); fprintf( outfile, "\tpopw %%gs\n" ); - /* Prepare return value and set flags accordingly */ - if ( !short_ret ) - fprintf( outfile, "\tshldl $16, %%eax, %%edx\n" ); - fprintf( outfile, "\torl %%eax, %%eax\n" ); - /* Return to return stub which will return to caller */ fprintf( outfile, "\tlret $12\n" ); } if (thunk) function_footer( outfile, "__wine_call_from_16_thunk" ); else if (reg_func) function_footer( outfile, "__wine_call_from_16_regs" ); - else if (short_ret) function_footer( outfile, "__wine_call_from_16_word" ); - else function_footer( outfile, "__wine_call_from_16_long" ); + else function_footer( outfile, "__wine_call_from_16" ); } @@ -935,17 +924,14 @@ void BuildRelays16( FILE *outfile ) fprintf( outfile, "%s\n", asm_globl("__wine_call16_start") ); - /* Standard CallFrom16 routine (WORD return) */ - BuildCallFrom16Core( outfile, FALSE, FALSE, TRUE ); - - /* Standard CallFrom16 routine (DWORD return) */ - BuildCallFrom16Core( outfile, FALSE, FALSE, FALSE ); + /* Standard CallFrom16 routine */ + BuildCallFrom16Core( outfile, FALSE, FALSE ); /* Register CallFrom16 routine */ - BuildCallFrom16Core( outfile, TRUE, FALSE, FALSE ); + BuildCallFrom16Core( outfile, TRUE, FALSE ); /* C16ThkSL CallFrom16 routine */ - BuildCallFrom16Core( outfile, FALSE, TRUE, FALSE ); + BuildCallFrom16Core( outfile, FALSE, TRUE ); /* Standard CallTo16 routine */ BuildCallTo16Core( outfile, 0 ); diff --git a/tools/winebuild/spec16.c b/tools/winebuild/spec16.c index b978a791ec1..798cd2068f2 100644 --- a/tools/winebuild/spec16.c +++ b/tools/winebuild/spec16.c @@ -28,29 +28,11 @@ #include #include -#include "wine/exception.h" #include "wine/winbase16.h" #include "build.h" -/******************************************************************* - * get_cs - */ -static inline unsigned short get_cs(void) -{ - unsigned short res = 0; -#ifdef __i386__ -# ifdef __GNUC__ - __asm__("movw %%cs,%w0" : "=r"(res)); -# elif defined(_MSC_VER) - __asm { mov res, cs } -# endif -#endif /* __i386__ */ - return res; -} - - /******************************************************************* * output_file_header * @@ -404,16 +386,11 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) unsigned int et_size, et_offset; char constructor[100], destructor[100]; - unsigned short code_selector = get_cs(); /* File header */ output_file_header( outfile ); fprintf( outfile, "static const char __wine_spec16_file_name[] = \"%s\";\n", spec->file_name ); - fprintf( outfile, "extern unsigned short __wine_call_from_16_word();\n" ); - fprintf( outfile, "extern unsigned int __wine_call_from_16_long();\n" ); - fprintf( outfile, "extern void __wine_call_from_16_regs();\n" ); - fprintf( outfile, "extern void __wine_call_from_16_thunk();\n" ); data_buffer = xmalloc( 0x10000 ); memset( data_buffer, 0, 16 ); @@ -471,7 +448,7 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) /* compute code and data sizes, set offsets, and output prototypes */ entrypoint_size = 2 + 5 + 4; /* pushw bp + pushl target + call */ - callfrom_size = 5 + 7 + 4 + 8; /* pushl relay + lcall cs:glue + lret n + args */ + callfrom_size = 5 + 7 + 10 + 2 + 8; /* pushl relay + lcall cs:glue + ret sequence + movl + args */ code_size = nTypes * callfrom_size; for (i = 0; i <= spec->limit; i++) @@ -508,7 +485,7 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) /* DOS header */ - fprintf( outfile, "\n#include \"pshpack1.h\"\n" ); + fprintf( outfile, "\n#pragma pack(1)\n" ); fprintf( outfile, "static const struct module_data\n{\n" ); fprintf( outfile, " struct\n {\n" ); fprintf( outfile, " unsigned short e_magic;\n" ); @@ -623,8 +600,8 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) fprintf( outfile, " unsigned char lcall;\n" ); /* lcall __FLATCS__:glue */ fprintf( outfile, " void *glue;\n" ); fprintf( outfile, " unsigned short flatcs;\n" ); - fprintf( outfile, " unsigned short lret;\n" ); /* lret $args */ - fprintf( outfile, " unsigned short args;\n" ); + fprintf( outfile, " unsigned short ret[5];\n" ); /* return sequence */ + fprintf( outfile, " unsigned short movl;\n" ); /* movl arg_types[1],arg_types[0](%esi) */ fprintf( outfile, " unsigned int arg_types[2];\n" ); fprintf( outfile, " } call[%d];\n", nTypes ); fprintf( outfile, " struct {\n" ); @@ -778,19 +755,37 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) arg_types[j / 10] |= type << (3 * (j % 10)); } if (typelist[i]->type == TYPE_VARARGS) arg_types[j / 10] |= ARG_VARARG << (3 * (j % 10)); - if (typelist[i]->flags & FLAG_REGISTER) arg_types[0] |= ARG_REGISTER; - if (typelist[i]->flags & FLAG_RET16) arg_types[0] |= ARG_RET16; - fprintf( outfile, " { 0x68, __wine_%s_CallFrom16_%s, 0x9a, __wine_call_from_16_%s,\n", - make_c_identifier(spec->file_name), profile, - (typelist[i]->flags & FLAG_REGISTER) ? "regs": - (typelist[i]->flags & FLAG_RET16) ? "word" : "long" ); - if (argsize) - fprintf( outfile, " 0x%04x, 0xca66, %d, { 0x%08x, 0x%08x } },\n", - code_selector, argsize, arg_types[0], arg_types[1] ); + fprintf( outfile, " { 0x68, __wine_%s_CallFrom16_%s, 0x9a, 0, 0,\n ", + make_c_identifier(spec->file_name), profile ); + + if (typelist[i]->flags & FLAG_REGISTER) + { + /* ret sequence: ret $n; nop */ + if (argsize) + fprintf( outfile, "{ 0xca66, %d, 0xb68d, 0x0000, 0x0000 },", argsize ); + else + fprintf( outfile, "{ 0xcb66, 0x748d, 0x0026, 0x748d, 0x0026 }," ); + } + else if (typelist[i]->flags & FLAG_RET16) + { + /* ret sequence: orl %eax,%eax; ret $n; nop */ + if (argsize) + fprintf( outfile, "{ 0xc009, 0xca66, %d, 0x748d, 0x0026 },", argsize ); + else + fprintf( outfile, "{ 0xc009, 0xcb66, 0xb68d, 0x0000, 0x0000 }," ); + } else - fprintf( outfile, " 0x%04x, 0xcb66, 0x9090, { 0x%08x, 0x%08x } },\n", - code_selector, arg_types[0], arg_types[1] ); + { + /* ret sequence: shld $16,%eax,%edx; orl %eax,%eax; ret $n [; nop] */ + if (argsize) + fprintf( outfile, "{ 0xa40f, 0x10c2, 0xc009, 0xca66, %d },", argsize ); + else + fprintf( outfile, "{ 0xa40f, 0x10c2, 0xc009, 0xcb66, 0xf689 }," ); + } + /* the movl is here so that the code contains only valid instructions, */ + /* it's never actually executed, we only care about the arg_types[] values */ + fprintf( outfile, " 0x86c7, { 0x%08x, 0x%08x } },\n", arg_types[0], arg_types[1] ); } fprintf( outfile, " },\n {\n" ); @@ -835,7 +830,7 @@ void BuildSpec16File( FILE *outfile, DLLSPEC *spec ) } fprintf( outfile, "};\n" ); - fprintf( outfile, "#include \"poppack.h\"\n\n" ); + fprintf( outfile, "#pragma pack()\n\n" ); /* Output the DLL constructor */