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:
Alexandre Julliard 2005-09-18 11:13:54 +00:00
parent 66f603ce4b
commit 89024a63d3
5 changed files with 69 additions and 55 deletions

View File

@ -519,7 +519,8 @@ static LONGLONG RELAY_CallFrom32( int ret_addr, ... )
* (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-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);
}

View File

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

View File

@ -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" ))
{
/* 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 );
}

View File

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

View File

@ -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 (UsePIC)
{
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-.L__wine_stub_getpc_%d(%%eax),%%ecx\n",
pos, i );
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-.L__wine_stub_getpc_%d(%%eax),%%ecx\n",
asm_name("__wine_spec_file_name"), i );
fprintf( outfile, "\tleal %s-1b(%%eax),%%ecx\n", asm_name("__wine_spec_file_name") );
fprintf( outfile, "\tpushl %%ecx\n" );
}
else
{
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) );
}