Make the users of wine_call_from_32_regs save %eax so that we don't
need a special hack in the import thunk. Added a get_pc_thunk_eax function to simplify the code a bit.
This commit is contained in:
parent
66f603ce4b
commit
89024a63d3
|
@ -516,10 +516,11 @@ static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
|
|||
* Stack layout (esp is context->Esp, not the current %esp):
|
||||
*
|
||||
* ...
|
||||
* (esp+4) first arg
|
||||
* (esp) return addr to caller
|
||||
* (esp-4) return addr to DEBUG_ENTRY_POINT
|
||||
* (esp-8) ptr to relay entry code for RELAY_CallFrom32Regs
|
||||
* (esp+4) first arg
|
||||
* (esp) return addr to caller
|
||||
* (esp-4) return addr to DEBUG_ENTRY_POINT
|
||||
* (esp-8) saved %eax
|
||||
* (esp-12) ptr to relay entry code for RELAY_CallFrom32Regs
|
||||
* ... >128 bytes space free to be modified (ensured by the assembly glue)
|
||||
*/
|
||||
void WINAPI __regs_RELAY_CallFrom32Regs( CONTEXT86 *context )
|
||||
|
@ -541,7 +542,8 @@ void WINAPI __regs_RELAY_CallFrom32Regs( CONTEXT86 *context )
|
|||
context->Esp += nb_args * sizeof(int);
|
||||
|
||||
entry_point = (BYTE *)relay->orig;
|
||||
assert( *entry_point == 0xe8 /* lcall */ );
|
||||
assert( entry_point[0] == 0x50 /* pushl %eax */ );
|
||||
assert( entry_point[1] == 0xe8 /* call */ );
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
{
|
||||
|
@ -564,7 +566,7 @@ void WINAPI __regs_RELAY_CallFrom32Regs( CONTEXT86 *context )
|
|||
memcpy( args_copy, args, nb_args * sizeof(args[0]) );
|
||||
args_copy[nb_args] = (int)context; /* append context argument */
|
||||
|
||||
call_entry_point( (entry_point + 5 + *(DWORD *)(entry_point + 5)), nb_args+1, args_copy );
|
||||
call_entry_point( (entry_point + 6 + *(DWORD *)(entry_point + 6)), nb_args+1, args_copy );
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
{
|
||||
|
@ -591,9 +593,10 @@ static BOOL is_register_entry_point( const BYTE *addr )
|
|||
const int *offset;
|
||||
const void *ptr;
|
||||
|
||||
if (*addr != 0xe8) return FALSE; /* not a call */
|
||||
if (addr[0] != 0x50) return FALSE; /* pushl %eax */
|
||||
if (addr[1] != 0xe8) return FALSE; /* call */
|
||||
/* check if call target is __wine_call_from_32_regs */
|
||||
offset = (const int *)(addr + 1);
|
||||
offset = (const int *)(addr + 2);
|
||||
if (*offset == (const char *)__wine_call_from_32_regs - (const char *)(offset + 1)) return TRUE;
|
||||
/* now check if call target is an import table jump to __wine_call_from_32_regs */
|
||||
addr = (const BYTE *)(offset + 1) + *offset;
|
||||
|
@ -606,11 +609,9 @@ static BOOL is_register_entry_point( const BYTE *addr )
|
|||
}
|
||||
else /* check for import thunk */
|
||||
{
|
||||
if (addr[0] != 0x50) return FALSE; /* pushl %eax */
|
||||
if (addr[1] != 0xe8 || addr[2] || addr[3] || addr[4] || addr[5]) return FALSE; /* call .+0 */
|
||||
if (addr[6] != 0x58) return FALSE; /* popl %eax */
|
||||
if (addr[7] != 0x8b || addr[8] != 0x80) return FALSE; /* movl offset(%eax),%eax */
|
||||
ptr = addr + 6 + *(const int *)(addr + 9);
|
||||
if (addr[0] != 0xe8) return FALSE; /* call get_pc_thunk */
|
||||
if (addr[5] != 0xff || addr[6] != 0xa0) return FALSE; /* jmp *offset(%eax) */
|
||||
ptr = addr + 5 + *(const int *)(addr + 7);
|
||||
}
|
||||
return (*(const char * const*)ptr == (char *)__wine_call_from_32_regs);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,7 @@ struct statvfs
|
|||
#ifdef __i386__
|
||||
#define DEFINE_REGS_ENTRYPOINT( name, args, pop_args ) \
|
||||
__ASM_GLOBAL_FUNC( name, \
|
||||
"pushl %eax\n\t" \
|
||||
"call " __ASM_NAME("__wine_call_from_32_regs") "\n\t" \
|
||||
".long " __ASM_NAME("__regs_") #name "-.\n\t" \
|
||||
".byte " #args "," #pop_args )
|
||||
|
|
|
@ -610,6 +610,21 @@ int resolve_imports( DLLSPEC *spec )
|
|||
return 1;
|
||||
}
|
||||
|
||||
/* output the get_pc thunk if needed */
|
||||
static void output_get_pc_thunk( FILE *outfile )
|
||||
{
|
||||
if (target_cpu != CPU_x86) return;
|
||||
if (!UsePIC) return;
|
||||
fprintf( outfile, "\n\t.text\n" );
|
||||
fprintf( outfile, "\t.align %d\n", get_alignment(4) );
|
||||
fprintf( outfile, "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
|
||||
fprintf( outfile, "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
|
||||
fprintf( outfile, "\tpopl %%eax\n" );
|
||||
fprintf( outfile, "\tpushl %%eax\n" );
|
||||
fprintf( outfile, "\tret\n" );
|
||||
output_function_size( outfile, "__wine_spec_get_pc_thunk_eax" );
|
||||
}
|
||||
|
||||
/* output a single import thunk */
|
||||
static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
|
||||
{
|
||||
|
@ -627,31 +642,15 @@ static void output_import_thunk( FILE *outfile, const char *name, const char *ta
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!strcmp( name, "__wine_call_from_32_regs" ))
|
||||
{
|
||||
/* special case: need to preserve all registers */
|
||||
fprintf( outfile, "\tpushl %%eax\n" );
|
||||
fprintf( outfile, "\tcall .L__wine_spec_%s\n", name );
|
||||
fprintf( outfile, ".L__wine_spec_%s:\n", name );
|
||||
fprintf( outfile, "\tpopl %%eax\n" );
|
||||
if (!strcmp( name, "__wine_call_from_16_regs" ))
|
||||
fprintf( outfile, "\t.byte 0x2e\n" );
|
||||
fprintf( outfile, "\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\n",
|
||||
table, pos, name );
|
||||
fprintf( outfile, "\txchgl %%eax,(%%esp)\n" );
|
||||
fprintf( outfile, "\tret\n" );
|
||||
}
|
||||
else if (!strcmp( name, "__wine_call_from_16_regs" ))
|
||||
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 .L__wine_spec_%s\n", name );
|
||||
fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
|
||||
fprintf( outfile, ".L__wine_spec_%s:\n", name );
|
||||
fprintf( outfile, "\tpopl %%eax\n" );
|
||||
fprintf( outfile, "\t.byte 0x2e\n" );
|
||||
fprintf( outfile, "\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\n",
|
||||
table, pos, 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" );
|
||||
|
@ -660,13 +659,11 @@ static void output_import_thunk( FILE *outfile, const char *name, const char *ta
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf( outfile, "\tcall .L__wine_spec_%s\n", name );
|
||||
fprintf( outfile, ".L__wine_spec_%s:\n", name );
|
||||
fprintf( outfile, "\tpopl %%eax\n" );
|
||||
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-.L__wine_spec_%s(%%eax)\n",
|
||||
table, pos, name );
|
||||
fprintf( outfile, "\tjmp *%s+%d-1b(%%eax)\n", table, pos );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1129,4 +1126,5 @@ void output_imports( FILE *outfile, DLLSPEC *spec )
|
|||
output_delayed_imports( outfile, spec );
|
||||
output_immediate_import_thunks( outfile );
|
||||
output_delayed_import_thunks( outfile, spec );
|
||||
if (nb_imports || has_stubs(spec)) output_get_pc_thunk( outfile );
|
||||
}
|
||||
|
|
|
@ -736,8 +736,9 @@ static void BuildCallTo32CBClient( FILE *outfile, BOOL isEx )
|
|||
*
|
||||
* Stack layout:
|
||||
* ...
|
||||
* (ebp+12) first arg
|
||||
* (ebp+8) ret addr to user code
|
||||
* (ebp+16) first arg
|
||||
* (ebp+12) ret addr to user code
|
||||
* (ebp+8) eax saved by relay code
|
||||
* (ebp+4) ret addr to relay code
|
||||
* (ebp+0) saved ebp
|
||||
* (ebp-128) buffer area to allow stack frame manipulation
|
||||
|
@ -767,12 +768,13 @@ static void BuildCallFrom32Regs( FILE *outfile )
|
|||
|
||||
/* Build the context structure */
|
||||
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
|
||||
fprintf( outfile, "\tpushfl\n" );
|
||||
fprintf( outfile, "\tpopl %%eax\n" );
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(EFlags) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl 0(%%ebp),%%eax\n" );
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Ebp) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl 4(%%ebp),%%eax\n" );
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %%ebx,%d(%%ebp)\n", CONTEXTOFFSET(Ebx) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %%ecx,%d(%%ebp)\n", CONTEXTOFFSET(Ecx) - STACK_SPACE );
|
||||
fprintf( outfile, "\tmovl %%edx,%d(%%ebp)\n", CONTEXTOFFSET(Edx) - STACK_SPACE );
|
||||
|
@ -797,7 +799,7 @@ static void BuildCallFrom32Regs( FILE *outfile )
|
|||
fprintf( outfile, "\tmovl $0x%x,%%eax\n", CONTEXT86_FULL );
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(ContextFlags) - STACK_SPACE );
|
||||
|
||||
fprintf( outfile, "\tmovl 8(%%ebp),%%eax\n" ); /* Get %eip at time of call */
|
||||
fprintf( outfile, "\tmovl 12(%%ebp),%%eax\n" ); /* Get %eip at time of call */
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eip) - STACK_SPACE );
|
||||
|
||||
/* Transfer the arguments */
|
||||
|
@ -807,14 +809,14 @@ static void BuildCallFrom32Regs( FILE *outfile )
|
|||
fprintf( outfile, "\tmovzbl 4(%%ebx),%%ecx\n" ); /* fetch number of args to copy */
|
||||
fprintf( outfile, "\tjecxz 1f\n" );
|
||||
fprintf( outfile, "\tsubl %%ecx,%%esp\n" );
|
||||
fprintf( outfile, "\tleal 12(%%ebp),%%esi\n" ); /* get %esp at time of call */
|
||||
fprintf( outfile, "\tleal 16(%%ebp),%%esi\n" ); /* get %esp at time of call */
|
||||
fprintf( outfile, "\tmovl %%esp,%%edi\n" );
|
||||
fprintf( outfile, "\tshrl $2,%%ecx\n" );
|
||||
fprintf( outfile, "\tcld\n" );
|
||||
fprintf( outfile, "\trep\n\tmovsl\n" ); /* copy args */
|
||||
|
||||
fprintf( outfile, "1:\tmovzbl 5(%%ebx),%%eax\n" ); /* fetch number of args to remove */
|
||||
fprintf( outfile, "\tleal 12(%%ebp,%%eax),%%eax\n" );
|
||||
fprintf( outfile, "\tleal 16(%%ebp,%%eax),%%eax\n" );
|
||||
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
|
||||
|
||||
/* Call the entry point */
|
||||
|
|
|
@ -292,21 +292,33 @@ static void output_stubs( FILE *outfile, DLLSPEC *spec )
|
|||
fprintf( outfile, "\t.align %d\n", get_alignment(4) );
|
||||
fprintf( outfile, "\t%s\n", func_declaration(name) );
|
||||
fprintf( outfile, "%s:\n", asm_name(name) );
|
||||
fprintf( outfile, "\tcall .L__wine_stub_getpc_%d\n", i );
|
||||
fprintf( outfile, ".L__wine_stub_getpc_%d:\n", i );
|
||||
fprintf( outfile, "\tpopl %%eax\n" );
|
||||
if (exp_name)
|
||||
|
||||
if (UsePIC)
|
||||
{
|
||||
fprintf( outfile, "\tleal .L__wine_stub_strings+%d-.L__wine_stub_getpc_%d(%%eax),%%ecx\n",
|
||||
pos, i );
|
||||
fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
|
||||
fprintf( outfile, "1:" );
|
||||
if (exp_name)
|
||||
{
|
||||
fprintf( outfile, "\tleal .L__wine_stub_strings+%d-1b(%%eax),%%ecx\n", pos );
|
||||
fprintf( outfile, "\tpushl %%ecx\n" );
|
||||
pos += strlen(exp_name) + 1;
|
||||
}
|
||||
else
|
||||
fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
|
||||
fprintf( outfile, "\tleal %s-1b(%%eax),%%ecx\n", asm_name("__wine_spec_file_name") );
|
||||
fprintf( outfile, "\tpushl %%ecx\n" );
|
||||
pos += strlen(exp_name) + 1;
|
||||
}
|
||||
else
|
||||
fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
|
||||
fprintf( outfile, "\tleal %s-.L__wine_stub_getpc_%d(%%eax),%%ecx\n",
|
||||
asm_name("__wine_spec_file_name"), i );
|
||||
fprintf( outfile, "\tpushl %%ecx\n" );
|
||||
{
|
||||
if (exp_name)
|
||||
{
|
||||
fprintf( outfile, "\tpushl $.L__wine_stub_strings+%d\n", pos );
|
||||
pos += strlen(exp_name) + 1;
|
||||
}
|
||||
else
|
||||
fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
|
||||
fprintf( outfile, "\tpushl $%s\n", asm_name("__wine_spec_file_name") );
|
||||
}
|
||||
fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
|
||||
fprintf( outfile, "\t%s\n", func_size(name) );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue