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.
This commit is contained in:
Alexandre Julliard 2005-09-18 12:25:22 +00:00
parent 2cf740619f
commit 96508ad686
9 changed files with 91 additions and 135 deletions

View File

@ -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"

View File

@ -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)

View File

@ -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;

View File

@ -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.@)
*/

View File

@ -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;
}

View File

@ -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 <poppack.h>
#define INVALID_HANDLE_VALUE16 ((HANDLE16) -1)

View File

@ -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:

View File

@ -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 );

View File

@ -28,29 +28,11 @@
#include <assert.h>
#include <ctype.h>
#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 */