Commit 6cfe757e authored by Victor Chiletto's avatar Victor Chiletto Committed by Alexandre Julliard

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.
parent 03a2d485
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include "winnls.h" #include "winnls.h"
#include "msvcrt.h" #include "msvcrt.h"
#include "mtdll.h" #include "mtdll.h"
#include "wine/asm.h"
#include "wine/debug.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
...@@ -1658,6 +1658,19 @@ int CDECL clearerr_s(FILE* file) ...@@ -1658,6 +1658,19 @@ int CDECL clearerr_s(FILE* file)
return 0; 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.@) * rewind (MSVCRT.@)
*/ */
......
...@@ -1591,6 +1591,47 @@ static void test_fopen_exclusive( void ) ...@@ -1591,6 +1591,47 @@ static void test_fopen_exclusive( void )
unlink(path); 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) START_TEST(misc)
{ {
int arg_c; int arg_c;
...@@ -1633,4 +1674,7 @@ START_TEST(misc) ...@@ -1633,4 +1674,7 @@ START_TEST(misc)
test_thread_storage(); test_thread_storage();
test_fenv(); test_fenv();
test_fopen_exclusive(); test_fopen_exclusive();
#if defined(__i386__)
test_rewind_i386_abi();
#endif
} }
...@@ -2470,7 +2470,8 @@ ...@@ -2470,7 +2470,8 @@
@ cdecl remquof(float float ptr) @ cdecl remquof(float float ptr)
@ cdecl remquol(double double ptr) remquo @ cdecl remquol(double double ptr) remquo
@ cdecl rename(str str) @ 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 rint(double) MSVCRT_rint
@ cdecl rintf(float) @ cdecl rintf(float)
@ cdecl rintl(double) MSVCRT_rint @ cdecl rintl(double) MSVCRT_rint
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment