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:
Victor Chiletto 2023-07-22 02:00:48 -03:00 committed by Alexandre Julliard
parent 03a2d4851b
commit 6cfe757eb7
3 changed files with 60 additions and 2 deletions

View file

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

View file

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

View file

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