Win32 register functions can now have arguments.

Simplified relay debugging for register functions.
This commit is contained in:
Alexandre Julliard 1999-05-13 16:13:17 +00:00
parent fd45627724
commit 06b978991b
5 changed files with 245 additions and 228 deletions

View File

@ -145,6 +145,7 @@ static BUILTIN32_DLL BuiltinDLLs[] =
};
extern void RELAY_CallFrom32();
extern void RELAY_CallFrom32Regs();
/***********************************************************************
* BUILTIN32_DoLoadImage
@ -362,29 +363,25 @@ static HMODULE BUILTIN32_DoLoadImage( BUILTIN32_DLL *dll )
}
switch(args)
{
case 0xfe: /* register func */
debug->call = 0xe8;
debug->callfrom32 = (DWORD)dll->descr->functions[i] -
(DWORD)&debug->ret;
debug->ret = 0x90; /* nop */
debug->args = 0;
*funcs = (LPVOID)((BYTE *)debug - addr);
break;
case 0xfd: /* forward */
case 0xff: /* stub or extern */
break;
default: /* normal function (stdcall or cdecl) */
default: /* normal function (stdcall or cdecl or register) */
if (TRACE_ON(relay)) {
debug->call = 0xe8; /* lcall relative */
debug->callfrom32 = (DWORD)RELAY_CallFrom32 -
(DWORD)&debug->ret;
if (args & 0x40) /* register func */
debug->callfrom32 = (DWORD)RELAY_CallFrom32Regs -
(DWORD)&debug->ret;
else
debug->callfrom32 = (DWORD)RELAY_CallFrom32 -
(DWORD)&debug->ret;
} else {
debug->call = 0xe9; /* ljmp relative */
debug->callfrom32 = (DWORD)dll->descr->functions[i] -
(DWORD)&debug->ret;
}
debug->ret = (args & 0x80) ? 0xc3 : 0xc2; /*ret/ret $n*/
debug->args = (args & 0x7f) * sizeof(int);
debug->args = (args & 0x3f) * sizeof(int);
*funcs = (LPVOID)((BYTE *)debug - addr);
break;
}

View File

@ -719,7 +719,7 @@ import ntdll.dll
698 stdcall UTRegister(long str str str ptr ptr ptr) UTRegister
699 stdcall UTUnRegister(long) UTUnRegister
700 stdcall UnMapLS(long) UnMapLS
701 register UnMapSLFixArray() UnMapSLFixArray
701 register UnMapSLFixArray(long long) UnMapSLFixArray
702 stdcall UnhandledExceptionFilter(ptr) UnhandledExceptionFilter
703 stdcall UninitializeCriticalSection(ptr) UninitializeCriticalSection
704 stdcall UnlockFile(long long long long long) UnlockFile
@ -926,3 +926,8 @@ import ntdll.dll
#1599 wrong ordinal (249 in Win32s's W32SCOMB.DLL) !
1599 stdcall Get16DLLAddress(long str) Get16DLLAddress
# Wine internal functions
1600 register SNOOP_Entry() SNOOP_Entry
1601 register SNOOP_Return() SNOOP_Return
1602 register RELAY_CallFrom32Regs() RELAY_CallFrom32Regs

View File

@ -10,9 +10,10 @@
#include "winnt.h"
#include "builtin32.h"
#include "selectors.h"
#include "stackframe.h"
#include "debugstr.h"
#include "debug.h"
#include "main.h"
#include "debugtools.h"
DEFAULT_DEBUG_CHANNEL(relay)
@ -59,6 +60,29 @@ int RELAY_ShowDebugmsgRelay(const char *func) {
return 1;
}
/***********************************************************************
* RELAY_PrintArgs
*/
static inline void RELAY_PrintArgs( int *args, int nb_args, unsigned int typemask )
{
while (nb_args--)
{
if ((typemask & 3) && HIWORD(*args))
{
if (typemask & 2)
DPRINTF( "%08x L%s", *args, debugstr_w((LPWSTR)*args) );
else
DPRINTF( "%08x %s", *args, debugstr_a((LPCSTR)*args) );
}
else DPRINTF( "%08x", *args );
if (nb_args) DPRINTF( "," );
args++;
typemask >>= 2;
}
}
/***********************************************************************
* RELAY_CallFrom32
*
@ -71,36 +95,23 @@ int RELAY_ShowDebugmsgRelay(const char *func) {
*/
int RELAY_CallFrom32( int ret_addr, ... )
{
int i, ret;
int ret;
char buffer[80];
unsigned int typemask;
FARPROC func;
unsigned int mask, typemask;
WORD fs;
int *args = &ret_addr;
int *args = &ret_addr + 1;
/* Relay addr is the return address for this function */
BYTE *relay_addr = (BYTE *)args[-1];
BYTE *relay_addr = (BYTE *)__builtin_return_address(0);
WORD nb_args = *(WORD *)(relay_addr + 1) / sizeof(int);
assert(TRACE_ON(relay));
func = (FARPROC)BUILTIN32_GetEntryPoint( buffer, relay_addr - 5,
&typemask );
DPRINTF( "Call %s(", buffer );
args++;
for (i = 0, mask = 3; i < nb_args; i++, mask <<= 2)
{
if (i) DPRINTF( "," );
if ((typemask & mask) && HIWORD(args[i]))
{
if (typemask & (2<<(2*i)))
DPRINTF( "%08x L%s", args[i], debugstr_w((LPWSTR)args[i]) );
else
DPRINTF( "%08x %s", args[i], debugstr_a((LPCSTR)args[i]) );
}
else DPRINTF( "%08x", args[i] );
}
GET_FS( fs );
DPRINTF( ") ret=%08x fs=%04x\n", ret_addr, fs );
func = (FARPROC)BUILTIN32_GetEntryPoint( buffer, relay_addr - 5, &typemask );
DPRINTF( "Call %s(", buffer );
RELAY_PrintArgs( args, nb_args, typemask );
GET_FS( fs );
DPRINTF( ") ret=%08x fs=%04x\n", ret_addr, fs );
if (*relay_addr == 0xc3) /* cdecl */
{
@ -141,8 +152,7 @@ int RELAY_CallFrom32( int ret_addr, ... )
args[6],args[7],args[8],args[9],args[10],args[11],
args[12],args[13],args[14],args[15]); break;
default:
ERR(relay, "Unsupported nb args %d\n",
nb_args );
ERR( "Unsupported nb of args %d\n", nb_args );
assert(FALSE);
}
}
@ -184,7 +194,7 @@ int RELAY_CallFrom32( int ret_addr, ... )
args[6],args[7],args[8],args[9],args[10],args[11],
args[12],args[13],args[14],args[15]); break;
default:
ERR(relay, "Unsupported nb args %d\n",nb_args );
ERR( "Unsupported nb of args %d\n", nb_args );
assert(FALSE);
}
}
@ -197,101 +207,94 @@ int RELAY_CallFrom32( int ret_addr, ... )
/***********************************************************************
* RELAY_CallFrom32Regs
*
* 'context' contains the register contents at the point of call of
* the REG_ENTRY_POINT. The stack layout of the stack pointed to by
* ESP_reg(&context) is as follows:
* Stack layout (esp is ESP_reg(context), not the current %esp):
*
* If debugmsg(relay) is OFF:
* ... ...
* (esp+4) args
* (esp) return addr to caller
* (esp-4) function entry point
*
* If debugmsg(relay) is ON:
* ... ...
* (esp+8) args
* (esp+4) return addr to caller
* (esp) return addr to DEBUG_ENTRY_POINT
* (esp-4) function entry point
*
* As the called function might change the stack layout
* (e.g. FT_Prolog, FT_ExitNN), we remove all modifications to the stack,
* so that the called function sees (in both cases):
*
* ... ...
* (esp+4) args
* ...
* (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
* ... >128 bytes space free to be modified (ensured by the assembly glue)
*
* NOTE: This routine makes no assumption about the relative position of
* its own stack to the stack pointed to by ESP_reg(&context),
* except that the latter must have >128 bytes space to grow.
* This means the assembly glue could even switch stacks completely
* (e.g. to allow for large stacks).
*
*/
void RELAY_CallFrom32Regs( CONTEXT context )
void WINAPI REGS_FUNC(RELAY_CallFrom32Regs)( CONTEXT *context )
{
typedef void (CALLBACK *entry_point_t)(CONTEXT *);
entry_point_t entry_point = *(entry_point_t*) (ESP_reg(&context) - 4);
unsigned int typemask;
char buffer[80];
int* args;
FARPROC func;
BYTE *entry_point;
__RESTORE_ES;
BYTE *relay_addr = *((BYTE **)ESP_reg(context) - 1);
WORD nb_args = *(WORD *)(relay_addr + 1) / sizeof(int);
if (!TRACE_ON(relay))
/* remove extra stuff from the stack */
EIP_reg(context) = STACK32_POP(context);
args = (int *)ESP_reg(context);
ESP_reg(context) += 4 * nb_args;
assert(TRACE_ON(relay));
entry_point = (BYTE *)BUILTIN32_GetEntryPoint( buffer, relay_addr - 5, &typemask );
assert( *entry_point == 0xe8 /* lcall */ );
func = *(FARPROC *)(entry_point + 5);
DPRINTF( "Call %s(", buffer );
RELAY_PrintArgs( args, nb_args, typemask );
DPRINTF( ") ret=%08lx fs=%04lx\n", EIP_reg(context), FS_reg(context) );
DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
EAX_reg(context), EBX_reg(context), ECX_reg(context),
EDX_reg(context), ESI_reg(context), EDI_reg(context) );
DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
EBP_reg(context), ESP_reg(context), DS_reg(context),
ES_reg(context), GS_reg(context), EFL_reg(context) );
/* Now call the real function */
switch(nb_args)
{
/* Simply call the entry point */
entry_point( &context );
case 0: func(context); break;
case 1: func(args[0],context); break;
case 2: func(args[0],args[1],context); break;
case 3: func(args[0],args[1],args[2],context); break;
case 4: func(args[0],args[1],args[2],args[3],context); break;
case 5: func(args[0],args[1],args[2],args[3],args[4],context); break;
case 6: func(args[0],args[1],args[2],args[3],args[4],args[5],context); break;
case 7: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],context); break;
case 8: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],context); break;
case 9: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
context); break;
case 10: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
args[9],context); break;
case 11: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
args[9],args[10],context); break;
case 12: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
args[9],args[10],args[11],context); break;
case 13: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
args[9],args[10],args[11],args[12],context); break;
case 14: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
args[9],args[10],args[11],args[12],args[13],context); break;
case 15: func(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8],
args[9],args[10],args[11],args[12],args[13],args[14],context); break;
case 16: func(args[0],args[1],args[2],args[3],args[4],args[5], args[6],args[7],args[8],
args[9],args[10],args[11],args[12],args[13],args[14],args[15],context); break;
default:
ERR( "Unsupported nb of args %d\n", nb_args );
assert(FALSE);
}
else
{
char buffer[80];
unsigned int typemask;
BYTE *relay_addr;
/*
* Fixup the context structure because of the extra parameter
* pushed by the relay debugging code.
* Note that this implicitly does a RET on the CALL from the
* DEBUG_ENTRY_POINT to the REG_ENTRY_POINT; setting the EIP register
* ensures that the assembly glue will directly return to the
* caller, just as in the non-debugging case.
*/
relay_addr = *(BYTE **) ESP_reg(&context);
if (BUILTIN32_GetEntryPoint( buffer, relay_addr - 5, &typemask )) {
/* correct win32 spec generated register function found.
* remove extra call stuff from stack
*/
ESP_reg(&context) += sizeof(BYTE *);
EIP_reg(&context) = *(DWORD *)ESP_reg(&context);
DPRINTF("Call %s(regs) ret=%08x\n", buffer, *(int *)ESP_reg(&context) );
DPRINTF(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
EAX_reg(&context), EBX_reg(&context), ECX_reg(&context),
EDX_reg(&context), ESI_reg(&context), EDI_reg(&context) );
DPRINTF(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
EBP_reg(&context), ESP_reg(&context), EIP_reg(&context),
DS_reg(&context), ES_reg(&context), FS_reg(&context),
GS_reg(&context), EFL_reg(&context) );
/* Now call the real function */
entry_point( &context );
DPRINTF("Ret %s() retval=regs ret=%08x\n", buffer, *(int *)ESP_reg(&context) );
DPRINTF(" EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx ESI=%08lx EDI=%08lx\n",
EAX_reg(&context), EBX_reg(&context), ECX_reg(&context),
EDX_reg(&context), ESI_reg(&context), EDI_reg(&context) );
DPRINTF(" EBP=%08lx ESP=%08lx EIP=%08lx DS=%04lx ES=%04lx FS=%04lx GS=%04lx EFL=%08lx\n",
EBP_reg(&context), ESP_reg(&context), EIP_reg(&context),
DS_reg(&context), ES_reg(&context), FS_reg(&context),
GS_reg(&context), EFL_reg(&context) );
} else
/* WINE internal register function found. Do not remove anything.
* Do not print any debuginfo (it is not a normal relayed one).
* Currently only used for snooping.
*/
entry_point( &context );
}
DPRINTF( "Ret %s() retval=%08lx ret=%08lx fs=%04lx\n",
buffer, EAX_reg(context), EIP_reg(context), FS_reg(context) );
DPRINTF(" eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
EAX_reg(context), EBX_reg(context), ECX_reg(context),
EDX_reg(context), ESI_reg(context), EDI_reg(context) );
DPRINTF(" ebp=%08lx esp=%08lx ds=%04lx es=%04lx gs=%04lx flags=%08lx\n",
EBP_reg(context), ESP_reg(context), DS_reg(context),
ES_reg(context), GS_reg(context), EFL_reg(context) );
}
#else /* __i386__ */
REGS_ENTRYPOINT(RELAY_CallFrom32Regs) { }
#endif /* __i386__ */

View File

@ -23,6 +23,9 @@ DEFAULT_DEBUG_CHANNEL(snoop)
char **debug_snoop_excludelist = NULL, **debug_snoop_includelist = NULL;
extern void SNOOP_Entry();
extern void SNOOP_Return();
#ifdef __i386__
#ifdef NEED_UNDERSCORE_PREFIX
@ -31,27 +34,6 @@ char **debug_snoop_excludelist = NULL, **debug_snoop_includelist = NULL;
# define PREFIX
#endif
/* Well, not exactly extern since they are in the same file (in the lines
* below). But the C Compiler doesn't see them there, so we have to help a bit.
*/
extern void SNOOP_Return();
extern void SNOOP_Entry();
__asm__(".align 4\n\t"
".globl "PREFIX"SNOOP_Entry\n\t"
".type "PREFIX"SNOOP_Entry,@function\n\t"
PREFIX"SNOOP_Entry:\n\t"
"pushl $"PREFIX"__regs_SNOOP_Entry\n\t"
"pushl $"PREFIX"CALL32_Regs\n\t"
"ret\n\t"
".align 4\n\t"
".globl "PREFIX"SNOOP_Return\n\t"
".type "PREFIX"SNOOP_Return,@function\n\t"
PREFIX"SNOOP_Return:\n\t"
"pushl $"PREFIX"__regs_SNOOP_Return\n\t"
"pushl $"PREFIX"CALL32_Regs\n\t"
"ret"
);
#include "pshpack1.h"
typedef struct tagSNOOP_FUN {
@ -267,8 +249,9 @@ SNOOP_PrintArg(DWORD x) {
return buf;
}
#define CALLER1REF (*(DWORD*)(ESP_reg(context)+4))
REGS_ENTRYPOINT(SNOOP_Entry) {
#define CALLER1REF (*(DWORD*)ESP_reg(context))
void WINAPI REGS_FUNC(SNOOP_Entry)( CONTEXT *context )
{
DWORD ordinal=0,entry = EIP_reg(context)-5;
SNOOP_DLL *dll = firstdll;
SNOOP_FUN *fun = NULL;
@ -336,18 +319,19 @@ REGS_ENTRYPOINT(SNOOP_Entry) {
if (fun->nrofargs>0) {
max = fun->nrofargs; if (max>16) max=16;
for (i=0;i<max;i++)
DPRINTF("%s%s",SNOOP_PrintArg(*(DWORD*)(ESP_reg(context)+8+sizeof(DWORD)*i)),(i<fun->nrofargs-1)?",":"");
DPRINTF("%s%s",SNOOP_PrintArg(*(DWORD*)(ESP_reg(context)+4+sizeof(DWORD)*i)),(i<fun->nrofargs-1)?",":"");
if (max!=fun->nrofargs)
DPRINTF(" ...");
} else if (fun->nrofargs<0) {
DPRINTF("<unknown, check return>");
ret->args = HeapAlloc(SystemHeap,0,16*sizeof(DWORD));
memcpy(ret->args,(LPBYTE)(ESP_reg(context)+8),sizeof(DWORD)*16);
memcpy(ret->args,(LPBYTE)(ESP_reg(context)+4),sizeof(DWORD)*16);
}
DPRINTF(") ret=%08lx fs=%04lx\n",(DWORD)ret->origreturn,FS_reg(context));
}
REGS_ENTRYPOINT(SNOOP_Return) {
void WINAPI REGS_FUNC(SNOOP_Return)( CONTEXT *context )
{
SNOOP_RETURNENTRY *ret = (SNOOP_RETURNENTRY*)(EIP_reg(context)-5);
/* We haven't found out the nrofargs yet. If we called a cdecl
@ -388,4 +372,8 @@ void SNOOP_RegisterDLL(HMODULE hmod,LPCSTR name,DWORD nrofordinals) {
FARPROC SNOOP_GetProcAddress(HMODULE hmod,LPCSTR name,DWORD ordinal,FARPROC origfun) {
return origfun;
}
REGS_ENTRYPOINT(SNOOP_Entry) { }
REGS_ENTRYPOINT(SNOOP_Return) { }
#endif /* !__i386__ */

View File

@ -458,12 +458,6 @@ static int ParseExportFunction( ORDDEF *odp )
odp->u.func.arg_types[i] = '\0';
if ((odp->type == TYPE_STDCALL) && !i)
odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
if ((odp->type == TYPE_REGISTER) && (SpecType == SPEC_WIN32) && i)
{
fprintf( stderr, "%s:%d: register functions cannot have arguments in Win32\n",
SpecName, Line );
return -1;
}
strcpy(odp->u.func.link_name, GetToken());
return 0;
}
@ -1074,11 +1068,13 @@ static int BuildSpec32File( char * specfile, FILE *outfile )
" \".globl " PREFIX "%s\\n\\t\"\n"
" \".type " PREFIX "%s,@function\\n\\t\"\n"
" \"" PREFIX "%s:\\n\\t\"\n"
" \"pushl $" PREFIX "__regs_%s\\n\\t\"\n"
" \"pushl $" PREFIX "CALL32_Regs\\n\\t\"\n"
" \"ret\");\n",
" \"call " PREFIX "CALL32_Regs\\n\\t\"\n"
" \".long " PREFIX "__regs_%s\\n\\t\"\n"
" \".byte %d,%d\");\n",
odp->u.func.link_name, odp->u.func.link_name,
odp->u.func.link_name, odp->u.func.link_name );
odp->u.func.link_name, odp->u.func.link_name,
4 * strlen(odp->u.func.arg_types),
4 * strlen(odp->u.func.arg_types) );
}
fprintf( outfile, "#ifndef __GNUC__\n" );
fprintf( outfile, "}\n" );
@ -1173,7 +1169,8 @@ static int BuildSpec32File( char * specfile, FILE *outfile )
for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
{
unsigned int j, mask = 0;
if ((odp->type == TYPE_STDCALL) || (odp->type == TYPE_CDECL))
if ((odp->type == TYPE_STDCALL) || (odp->type == TYPE_CDECL) ||
(odp->type == TYPE_REGISTER))
for (j = 0; odp->u.func.arg_types[j]; j++)
{
if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2);
@ -1211,12 +1208,12 @@ static int BuildSpec32File( char * specfile, FILE *outfile )
case TYPE_CDECL:
args = 0x80 | (unsigned char)strlen(odp->u.func.arg_types);
break;
case TYPE_REGISTER:
args = 0x40 | (unsigned char)strlen(odp->u.func.arg_types);
break;
case TYPE_FORWARD:
args = 0xfd;
break;
case TYPE_REGISTER:
args = 0xfe;
break;
default:
args = 0xff;
break;
@ -2542,15 +2539,25 @@ static void BuildCallTo32LargeStack( FILE *outfile )
* 'args' is the number of dword arguments.
*
* Stack layout:
* ... ...
* (esp+336) ret addr (or relay addr when debugging(relay) is on)
* (esp+332) entry point
* (esp+204) buffer area to allow stack frame manipulation
* (esp+0) CONTEXT struct
* ...
* (ebp+12) first arg
* (ebp+8) ret addr to user code
* (ebp+4) ret addr to relay code
* (ebp+0) saved ebp
* (ebp-128) buffer area to allow stack frame manipulation
* (ebp-332) CONTEXT struct
* (ebp-336) CONTEXT *argument
* .... other arguments copied from (ebp+12)
*
* The entry point routine is called with a CONTEXT* extra argument,
* following the normal args. In this context structure, EIP_reg
* contains the return address to user code, and ESP_reg the stack
* pointer on return (with the return address and arguments already
* removed).
*/
static void BuildCallFrom32Regs( FILE *outfile )
{
#define STACK_SPACE 128
static const int STACK_SPACE = 128 + sizeof(CONTEXT);
/* Function header */
@ -2562,85 +2569,102 @@ static void BuildCallFrom32Regs( FILE *outfile )
fprintf( outfile, PREFIX "CALL32_Regs:\n" );
/* Allocate some buffer space on the stack */
fprintf( outfile, "\tpushl %%ebp\n" );
fprintf( outfile, "\tmovl %%esp,%%ebp\n ");
fprintf( outfile, "\tleal -%d(%%esp), %%esp\n", STACK_SPACE );
/* Build the context structure */
fprintf( outfile, "\tpushw $0\n" );
fprintf( outfile, "\t.byte 0x66\n\tpushl %%ss\n" );
fprintf( outfile, "\tpushl %%eax\n" ); /* %esp place holder */
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
fprintf( outfile, "\tpushfl\n" );
fprintf( outfile, "\tpushw $0\n" );
fprintf( outfile, "\t.byte 0x66\n\tpushl %%cs\n" );
fprintf( outfile, "\tpushl %d(%%esp)\n", 16+STACK_SPACE+4 ); /* %eip at time of call */
fprintf( outfile, "\tpushl %%ebp\n" );
fprintf( outfile, "\tpushl %%eax\n" );
fprintf( outfile, "\tpushl %%ecx\n" );
fprintf( outfile, "\tpushl %%edx\n" );
fprintf( outfile, "\tpushl %%ebx\n" );
fprintf( outfile, "\tpushl %%esi\n" );
fprintf( outfile, "\tpushl %%edi\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 %%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 );
fprintf( outfile, "\tmovl %%esi,%d(%%ebp)\n", CONTEXTOFFSET(Esi) - STACK_SPACE );
fprintf( outfile, "\tmovl %%edi,%d(%%ebp)\n", CONTEXTOFFSET(Edi) - STACK_SPACE );
fprintf( outfile, "\txorl %%eax,%%eax\n" );
fprintf( outfile, "\tmovw %%ds,%%ax\n" );
fprintf( outfile, "\tpushl %%eax\n" );
fprintf( outfile, "\tmovw %%cs,%%ax\n" );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegCs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%es,%%ax\n" );
fprintf( outfile, "\tpushl %%eax\n" );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegEs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%fs,%%ax\n" );
fprintf( outfile, "\tpushl %%eax\n" );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegFs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%gs,%%ax\n" );
fprintf( outfile, "\tpushl %%eax\n" );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegGs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%ss,%%ax\n" );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegSs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%ds,%%ax\n" );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(SegDs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%ax,%%es\n" ); /* set %es equal to %ds just in case */
fprintf( outfile, "\tleal -%d(%%esp),%%esp\n",
sizeof(FLOATING_SAVE_AREA) + 6 * sizeof(DWORD) /* DR regs */ );
fprintf( outfile, "\tpushl $0x0001001f\n" ); /* ContextFlags */
fprintf( outfile, "\tmovl $0x%x,%%eax\n", CONTEXT_FULL );
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(ContextFlags) - STACK_SPACE );
fprintf( outfile, "\tfsave %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
fprintf( outfile, "\tmovl 8(%%ebp),%%eax\n" ); /* Get %eip at time of call */
fprintf( outfile, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Eip) - STACK_SPACE );
fprintf( outfile, "\tleal %d(%%esp),%%eax\n",
sizeof(CONTEXT) + STACK_SPACE + 4 ); /* %esp at time of call */
fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Esp) );
/* Transfer the arguments */
fprintf( outfile, "\tcall " PREFIX "RELAY_CallFrom32Regs\n" );
fprintf( outfile, "\tmovl 4(%%ebp),%%ebx\n" ); /* get relay code addr */
fprintf( outfile, "\tpushl %%esp\n" ); /* push ptr to context struct */
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, "\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, "\tmovl %%eax,%d(%%ebp)\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
/* Call the entry point */
fprintf( outfile, "\tcall *0(%%ebx)\n" );
/* Store %eip and %ebp onto the new stack */
fprintf( outfile, "\tmovl %d(%%ebp),%%edx\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eip) - STACK_SPACE );
fprintf( outfile, "\tmovl %%eax,-4(%%edx)\n" );
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Ebp) - STACK_SPACE );
fprintf( outfile, "\tmovl %%eax,-8(%%edx)\n" );
/* Restore the context structure */
fprintf( outfile, "\tfrstor %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
/* Store %eip value onto the new stack */
fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Eip) );
fprintf( outfile, "\tmovl %d(%%esp),%%ebx\n", CONTEXTOFFSET(Esp) );
fprintf( outfile, "\tmovl %%eax,0(%%ebx)\n" );
/* Restore all registers */
fprintf( outfile, "\tleal %d(%%esp),%%esp\n",
sizeof(FLOATING_SAVE_AREA) + 7 * sizeof(DWORD) );
fprintf( outfile, "\tpopl %%eax\n" );
fprintf( outfile, "\tmovw %%ax,%%gs\n" );
fprintf( outfile, "\tpopl %%eax\n" );
fprintf( outfile, "\tmovw %%ax,%%fs\n" );
fprintf( outfile, "\tpopl %%eax\n" );
/* Note: we don't bother to restore %cs, %ds and %ss
* changing them in 32-bit code is a recipe for disaster anyway
*/
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegEs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%ax,%%es\n" );
fprintf( outfile, "\tpopl %%eax\n" );
fprintf( outfile, "\tmovw %%ax,%%ds\n" );
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegFs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%ax,%%fs\n" );
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(SegGs) - STACK_SPACE );
fprintf( outfile, "\tmovw %%ax,%%gs\n" );
fprintf( outfile, "\tpopl %%edi\n" );
fprintf( outfile, "\tpopl %%esi\n" );
fprintf( outfile, "\tpopl %%ebx\n" );
fprintf( outfile, "\tpopl %%edx\n" );
fprintf( outfile, "\tpopl %%ecx\n" );
fprintf( outfile, "\tpopl %%eax\n" );
fprintf( outfile, "\tpopl %%ebp\n" );
fprintf( outfile, "\tleal 8(%%esp),%%esp\n" ); /* skip %eip and %cs */
fprintf( outfile, "\tmovl %d(%%ebp),%%edi\n", CONTEXTOFFSET(Edi) - STACK_SPACE );
fprintf( outfile, "\tmovl %d(%%ebp),%%esi\n", CONTEXTOFFSET(Esi) - STACK_SPACE );
fprintf( outfile, "\tmovl %d(%%ebp),%%edx\n", CONTEXTOFFSET(Edx) - STACK_SPACE );
fprintf( outfile, "\tmovl %d(%%ebp),%%ecx\n", CONTEXTOFFSET(Ecx) - STACK_SPACE );
fprintf( outfile, "\tmovl %d(%%ebp),%%ebx\n", CONTEXTOFFSET(Ebx) - STACK_SPACE );
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(EFlags) - STACK_SPACE );
fprintf( outfile, "\tpushl %%eax\n" );
fprintf( outfile, "\tpopfl\n" );
fprintf( outfile, "\tpopl %%esp\n" );
fprintf( outfile, "\tret\n" );
fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", CONTEXTOFFSET(Eax) - STACK_SPACE );
#undef STACK_SPACE
fprintf( outfile, "\tmovl %d(%%ebp),%%ebp\n", CONTEXTOFFSET(Esp) - STACK_SPACE );
fprintf( outfile, "\tleal -8(%%ebp),%%esp\n" );
fprintf( outfile, "\tpopl %%ebp\n" );
fprintf( outfile, "\tret\n" );
}