diff --git a/src/hook.c b/src/hook.c index 28a65bf538..1f8da14bf6 100644 --- a/src/hook.c +++ b/src/hook.c @@ -30,9 +30,7 @@ void* g_hooktableaddress = 0; int g_hooktableoffset = 0; int g_maxhooks = 1000; -registers _returnRegisters; - -void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister, bool useReturnRegisters) +void hookfunc(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister) { int i = 0; char data[100]; @@ -55,73 +53,6 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in int rargssize = numrargs * 4; - data[i++] = 0x50; // push eax - - // move stack down for possible existing arguments - for (int j = 0; j < stacksize; j++) { - data[i++] = 0x8B; // mov eax, [esp+x] - data[i++] = 0x44; - data[i++] = 0xE4; - data[i++] = (signed char)((4 * (stacksize - j)) + 4); - - data[i++] = 0x89; // mov [esp+x], eax - data[i++] = 0x44; - data[i++] = 0xE4; - data[i++] = (signed char)((4 * (stacksize - j)) - ((registerssaved + stacksize) * 4)); - } - - if (numrargs > 0) { - // push the registers to be on the stack to access as arguments - data[i++] = 0x83; // add esp, x - data[i++] = 0xC4; - data[i++] = -((registerssaved + stacksize) * 4) + 4; - - for (signed int j = numrargs - 1; j >= 0; j--) { - switch (registerargs[j]) { - case EAX: data[i++] = 0x50; break; - case EBX: data[i++] = 0x53; break; - case ECX: data[i++] = 0x51; break; - case EDX: data[i++] = 0x52; break; - case ESI: data[i++] = 0x56; break; - case EDI: data[i++] = 0x57; break; - case EBP: data[i++] = 0x55; break; - } - } - - data[i++] = 0x83; // add esp, x - data[i++] = 0xC4; - data[i++] = rargssize + ((registerssaved + stacksize) * 4) - 4; - } - - - data[i++] = 0xE8; // call - data[i++] = 0x00; - data[i++] = 0x00; - data[i++] = 0x00; - data[i++] = 0x00; - - int sizec = i; - - data[i++] = 0x8B; // push eax, [esp] - puts eip in eax - data[i++] = 0x04; - data[i++] = 0xE4; - - data[i++] = 0x83; // add eax, x - data[i++] = 0xC0; - int sizeoffset = i; - data[i++] = 0; // set to returnlocation offset later - - data[i++] = 0x89; // mov [esp-20h], eax - put return address on stack - data[i++] = 0x44; - data[i++] = 0xE4; - data[i++] = (signed char)(-(registerssaved * 4) - rargssize - (stacksize * 4)) + 4; - - data[i++] = 0x83; // add esp, x - data[i++] = 0xC4; - data[i++] = 4; - - data[i++] = 0x58; // pop eax - if (!(registersreturned & EAX)) { data[i++] = 0x50; // push eax } @@ -144,15 +75,51 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in data[i++] = 0x57; // push edi } - data[i++] = 0x83; // sub esp, x - data[i++] = 0xEC; - data[i++] = 4 + (stacksize * 4) + rargssize; + data[i++] = 0x50; //push eax + data[i++] = 0x89; //mov eax, esp + data[i++] = 0xE0; + data[i++] = 0x83; //sub eax, (0xC + numargs*4) & 0xF + data[i++] = 0xE8; + data[i++] = (0xC + numrargs * 4) & 0xF; + data[i++] = 0x83; //and eax, 0xC + data[i++] = 0xE0; + data[i++] = 0x0C; + data[i++] = 0xA3; //mov [0x9ABDA8], eax + data[i++] = 0xA8; + data[i++] = 0xBD; + data[i++] = 0x9A; + data[i++] = 0x00; + data[i++] = 0x58; //pop eax + data[i++] = 0x2B; //sub esp, [0x9ABDA8] + data[i++] = 0x25; + data[i++] = 0xA8; + data[i++] = 0xBD; + data[i++] = 0x9A; + data[i++] = 0x00; - data[i++] = 0xE9; // jmp + // work out distance to nearest 0xC + // (esp - numargs * 4) & 0xC + // move to align - 4 + // save that amount + + if (numrargs > 0) { + // push the registers to be on the stack to access as arguments + for (signed int j = numrargs - 1; j >= 0; j--) { + switch (registerargs[j]) { + case EAX: data[i++] = 0x50; break; + case EBX: data[i++] = 0x53; break; + case ECX: data[i++] = 0x51; break; + case EDX: data[i++] = 0x52; break; + case ESI: data[i++] = 0x56; break; + case EDI: data[i++] = 0x57; break; + case EBP: data[i++] = 0x55; break; + } + } + } + + data[i++] = 0xE8; // call *((int *)&data[i]) = (newaddress - address - i - 4); i += 4; - data[sizeoffset] = i - sizec; - // returnlocation: switch (eaxDestinationRegister) { @@ -188,19 +155,17 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in break; } - if (useReturnRegisters) { - // mov ebx, [_returnRegisters.ebx] - data[i++] = 0x8B; - data[i++] = 0x1C; - data[i++] = 0x25; - *((uint32*)&data[i]) = (uint32)(&_returnRegisters.ebx); - i += 4; - } - data[i++] = 0x83; // sub esp, x data[i++] = 0xEC; data[i++] = (signed char)(stacksize * -4) - rargssize; + data[i++] = 0x03; //add esp, [0x9ABDA8] + data[i++] = 0x25; + data[i++] = 0xA8; + data[i++] = 0xBD; + data[i++] = 0x9A; + data[i++] = 0x00; + if (!(registersreturned & EDI)) { data[i++] = 0x5F; // pop edi } @@ -233,7 +198,7 @@ void hookfunc(int address, int newaddress, int stacksize, int registerargs[], in #endif // _WIN32 } -void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister, bool useReturnRegisters) +void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister) { if (!g_hooktableaddress) { size_t size = g_maxhooks * 100; @@ -263,11 +228,6 @@ void addhook(int address, int newaddress, int stacksize, int registerargs[], int // We own the pages with PROT_WRITE | PROT_EXEC, we can simply just memcpy the data memcpy((void *)address, data, i); #endif // _WIN32 - hookfunc(hookaddress, newaddress, stacksize, registerargs, registersreturned, eaxDestinationRegister, useReturnRegisters); + hookfunc(hookaddress, newaddress, stacksize, registerargs, registersreturned, eaxDestinationRegister); g_hooktableoffset++; -} - -void hook_setreturnregisters(registers *regs) -{ - _returnRegisters = *regs; } \ No newline at end of file diff --git a/src/hook.h b/src/hook.h index 38cf1d1198..7f2289f059 100644 --- a/src/hook.h +++ b/src/hook.h @@ -21,9 +21,6 @@ #ifndef _HOOK_H_ #define _HOOK_H_ -#include "addresses.h" -#include "common.h" - enum REGISTER_ARGS { EAX = 1 << 0, EBX = 1 << 1, @@ -35,7 +32,6 @@ enum REGISTER_ARGS { END = 0 }; -void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister, bool useReturnRegisters); -void hook_setreturnregisters(registers *regs); +void addhook(int address, int newaddress, int stacksize, int registerargs[], int registersreturned, int eaxDestinationRegister); #endif \ No newline at end of file diff --git a/src/openrct2.c b/src/openrct2.c index 0018f36252..26a8bdf27e 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -40,14 +40,14 @@ #include "util/util.h" #include "world/mapgen.h" -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) #include #include #include #include #include #include -#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#endif // defined(__unix__) int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE; utf8 gOpenRCT2StartupActionPath[512] = { 0 }; @@ -59,11 +59,11 @@ bool gOpenRCT2Headless = false; bool gOpenRCT2ShowChangelog; -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) void *gDataSegment; void *gTextSegment; int gExeFd; -#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#endif // defined(__unix__) /** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to 0. */ int _finished; @@ -471,7 +471,7 @@ static bool openrct2_setup_rct2_segment() { // POSIX OSes will run OpenRCT2 as a native application and then load in the Windows PE, mapping the appropriate addresses as // necessary. Windows does not need to do this as OpenRCT2 runs as a DLL loaded from the Windows PE. -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) #define RDATA_OFFSET 0x004A4000 #define DATASEG_OFFSET 0x005E2000 @@ -513,8 +513,45 @@ static bool openrct2_setup_rct2_segment() off_t file_size = 6750208; int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB + int pageSize = getpagesize(); + int numPages = (len + pageSize - 1) / pageSize; + unsigned char *dummy = malloc(numPages); + int err = mincore((void *)0x8a4000, len, dummy); + bool pagesDirty = false; + if (err != 0) + { + err = errno; +#ifdef __linux__ + // On Linux ENOMEM means all requested range is unmapped + if (err != ENOMEM) + { + pagesDirty = true; + perror("mincore"); + } +#else + pagesDirty = true; + perror("mincore"); +#endif // __linux__ + } else { + log_warning("mincore ok"); + for (int i = 0; i < numPages; i++) + { + if (dummy[i] != 0) + { + pagesDirty = true; + void *start = (void *)0x8a4000 + i * pageSize; + void *end = (void *)0x8a4000 + (i + 1) * pageSize - 1; + log_warning("page %p - %p has flags: %x, you're in for bad time!", start, end, dummy[i]); + } + } + } + free(dummy); + if (pagesDirty) + { + log_error("Found already mapped pages in region we want to claim. This means something accessed memory before we got to and following mmap (or next malloc) call will likely fail."); + } // section: rw data - gDataSegment = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, 0, 0); + gDataSegment = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, -1, 0); if (gDataSegment != (void *)0x8a4000) { log_fatal("mmap failed to get required offset for data segment! got %p, expected %p, errno = %d", gDataSegment, (void *)(0x8a4000), errno); exit(1); @@ -530,7 +567,7 @@ static bool openrct2_setup_rct2_segment() } void *fbase = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, gExeFd, 0); - int err = errno; + err = errno; log_warning("mmapped file to %p", fbase); if (fbase == MAP_FAILED) { @@ -548,7 +585,7 @@ static bool openrct2_setup_rct2_segment() err = errno; log_error("Failed to unmap file! errno = %d", err); } -#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#endif // defined(__unix__) // Check that the expected data is at various addresses. // Start at 0x9a6000, which is start of .data, to skip the region containing addresses to DLL @@ -572,7 +609,7 @@ static bool openrct2_setup_rct2_segment() static bool openrct2_release_rct2_segment() { bool result = true; -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB int err; err = munmap(gDataSegment, len); @@ -597,7 +634,7 @@ static bool openrct2_release_rct2_segment() log_error("Failed to close file! errno = %d", err); result = false; } -#endif // defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#endif // defined(__unix__) return result; } @@ -606,14 +643,14 @@ static bool openrct2_release_rct2_segment() */ static void openrct2_setup_rct2_hooks() { - addhook(0x006E732D, (int)gfx_set_dirty_blocks, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0, 0, false); // remove when all callers are decompiled - addhook(0x006E7499, (int)gfx_redraw_screen_rect, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0, 0, false); // remove when 0x6E7FF3 is decompiled - addhook(0x0069A42F, (int)peep_window_state_update, 0, (int[]){ ESI, END }, 0, 0, false); // remove when all callers are decompiled - addhook(0x006BB76E, (int)audio_play_sound_panned, 0, (int[]){EAX, EBX, ECX, EDX, EBP, END}, EAX, 0, false); // remove when all callers are decompiled - addhook(0x006C42D9, (int)scrolling_text_setup, 0, (int[]){EAX, ECX, EBP, END}, 0, EBX, false); // remove when all callers are decompiled - addhook(0x006C2321, (int)gfx_get_string_width, 0, (int[]){ESI, END}, 0, ECX, false); // remove when all callers are decompiled - addhook(0x006C2555, (int)format_string, 0, (int[]){EDI, EAX, ECX, END}, 0, 0, false); // remove when all callers are decompiled - addhook(0x006DAB4C, (int)sub_6DAB4C, 0, (int[]){ESI, END}, 0, EAX, true); // remove when all callers are decompiled + addhook(0x006E732D, (int)gfx_set_dirty_blocks, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0, 0); // remove when all callers are decompiled + addhook(0x006E7499, (int)gfx_redraw_screen_rect, 0, (int[]){ EAX, EBX, EDX, EBP, END }, 0, 0); // remove when 0x6E7FF3 is decompiled + addhook(0x006B752C, (int)ride_crash, 0, (int[]){ EDX, EBX, END }, 0, 0); // remove when all callers are decompiled + addhook(0x0069A42F, (int)peep_window_state_update, 0, (int[]){ ESI, END }, 0, 0); // remove when all callers are decompiled + addhook(0x006BB76E, (int)audio_play_sound_panned, 0, (int[]){EAX, EBX, ECX, EDX, EBP, END}, 0, EAX); // remove when all callers are decompiled + addhook(0x006C42D9, (int)scrolling_text_setup, 0, (int[]){EAX, ECX, EBP, END}, 0, EBX); // remove when all callers are decompiled + addhook(0x006C2321, (int)gfx_get_string_width, 0, (int[]){ESI, END}, 0, ECX); // remove when all callers are decompiled + addhook(0x006C2555, (int)format_string, 0, (int[]){EDI, EAX, ECX, END}, 0, 0); // remove when all callers are decompiled } #if _MSC_VER >= 1900 @@ -628,4 +665,4 @@ FILE **__iob_func() streams[2] = stderr; return streams; } -#endif +#endif \ No newline at end of file diff --git a/src/ride/vehicle.c b/src/ride/vehicle.c index 40e102fefc..aefaa12199 100644 --- a/src/ride/vehicle.c +++ b/src/ride/vehicle.c @@ -5927,6 +5927,13 @@ int sub_6DAB4C(rct_vehicle *vehicle, int *outStation) { registers regs = { 0 }; + ////////////////////////////////////////////////////////////////////////////////////////// + regs.esi = (int)vehicle; + RCT2_CALLFUNC_Y(0x006DAB4C, ®s); + if (outStation != NULL) *outStation = regs.ebx; + return regs.eax; + ////////////////////////////////////////////////////////////////////////////////////////// + rct_ride *ride = GET_RIDE(vehicle->ride); rct_ride_type *rideEntry = GET_RIDE_ENTRY(vehicle->ride_subtype); rct_ride_type_vehicle *vehicleEntry = vehicle_get_vehicle_entry(vehicle); @@ -7421,7 +7428,7 @@ loc_6DD069: regs.ebx = RCT2_GLOBAL(0x00F64E1C, uint32); end: - hook_setreturnregisters(®s); + // hook_setreturnregisters(®s); return regs.eax; }