mirror of
git://source.winehq.org/git/wine.git
synced 2024-07-24 06:26:23 +00:00
msvcrt, ucrtbase: Introduce rewind_preserve_stack.
This is a small thunk to rewind that preserves the first argument passed. This is needed because on some versions of GCC, rewind's call to _unlock_file is tail-call optimized, which modifies the stack.
This commit is contained in:
parent
03a2d4851b
commit
6cfe757eb7
|
@ -42,7 +42,7 @@
|
|||
#include "winnls.h"
|
||||
#include "msvcrt.h"
|
||||
#include "mtdll.h"
|
||||
|
||||
#include "wine/asm.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
|
||||
|
@ -1658,6 +1658,19 @@ int CDECL clearerr_s(FILE* file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
/* Stack preserving thunk for rewind
|
||||
* needed for the UIO mod for Fallout: New Vegas
|
||||
*/
|
||||
__ASM_GLOBAL_FUNC(rewind_preserve_stack,
|
||||
"pushl 4(%esp)\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
|
||||
"call "__ASM_NAME("rewind") "\n\t"
|
||||
"addl $4,%esp\n\t"
|
||||
__ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
|
||||
"ret")
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* rewind (MSVCRT.@)
|
||||
*/
|
||||
|
|
|
@ -1591,6 +1591,47 @@ static void test_fopen_exclusive( void )
|
|||
unlink(path);
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
#include "pshpack1.h"
|
||||
struct rewind_thunk {
|
||||
BYTE push_esp[4]; /* push [esp+0x4] */
|
||||
BYTE call_rewind; /* call */
|
||||
DWORD rewind_addr; /* relative addr of rewind */
|
||||
BYTE pop_eax; /* pop eax */
|
||||
BYTE ret; /* ret */
|
||||
};
|
||||
#include "poppack.h"
|
||||
|
||||
static FILE * (CDECL *test_rewind_wrapper)(FILE *fp);
|
||||
|
||||
static void test_rewind_i386_abi(void)
|
||||
{
|
||||
FILE *fp_in, *fp_out;
|
||||
|
||||
struct rewind_thunk *thunk = VirtualAlloc(NULL, sizeof(*thunk), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
|
||||
thunk->push_esp[0] = 0xff;
|
||||
thunk->push_esp[1] = 0x74;
|
||||
thunk->push_esp[2] = 0x24;
|
||||
thunk->push_esp[3] = 0x04;
|
||||
|
||||
thunk->call_rewind = 0xe8;
|
||||
thunk->rewind_addr = (BYTE *) rewind - (BYTE *) (&thunk->rewind_addr + 1);
|
||||
|
||||
thunk->pop_eax = 0x58;
|
||||
thunk->ret = 0xc3;
|
||||
|
||||
test_rewind_wrapper = (void *) thunk;
|
||||
|
||||
fp_in = fopen("rewind_abi.tst", "wb");
|
||||
fp_out = test_rewind_wrapper(fp_in);
|
||||
ok(fp_in == fp_out, "rewind modified the first argument in the stack\n");
|
||||
|
||||
fclose(fp_in);
|
||||
unlink("rewind_abi.tst");
|
||||
}
|
||||
#endif
|
||||
|
||||
START_TEST(misc)
|
||||
{
|
||||
int arg_c;
|
||||
|
@ -1633,4 +1674,7 @@ START_TEST(misc)
|
|||
test_thread_storage();
|
||||
test_fenv();
|
||||
test_fopen_exclusive();
|
||||
#if defined(__i386__)
|
||||
test_rewind_i386_abi();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -2470,7 +2470,8 @@
|
|||
@ cdecl remquof(float float ptr)
|
||||
@ cdecl remquol(double double ptr) remquo
|
||||
@ cdecl rename(str str)
|
||||
@ cdecl rewind(ptr)
|
||||
@ cdecl -arch=i386 rewind(ptr) rewind_preserve_stack
|
||||
@ cdecl -arch=!i386 rewind(ptr)
|
||||
@ cdecl rint(double) MSVCRT_rint
|
||||
@ cdecl rintf(float)
|
||||
@ cdecl rintl(double) MSVCRT_rint
|
||||
|
|
Loading…
Reference in a new issue