From c9be2e1bc99a60ea446a46bf6fb27013d0d1f5ff Mon Sep 17 00:00:00 2001 From: LRFLEW Date: Tue, 8 Dec 2015 21:06:21 -0600 Subject: [PATCH] Resolved struct packing error and crash on OS X --- CMakeLists.txt | 20 ++++++++++++- src/network/network.h | 6 ++++ src/openrct2.c | 67 +++++++++++++++++++++++++++++-------------- 3 files changed, 70 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae1be6c228..36fa04b30d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,7 +65,7 @@ if (UNIX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32 -std=gnu++11 -fno-omit-frame-pointer -fno-pie") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") if (APPLE) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -sectcreate rct2_text __text /Users/kkirbatski/Desktop/openrct2_text -sectcreate rct2_data __data /Users/kkirbatski/Desktop/openrct2_data -segaddr rct2_data 0x8a4000 -segprot rct2_data rwx rwx -segaddr rct2_text 0x4010000 -segprot rct2_text rwx rwx -fno-pie -read_only_relocs suppress") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -sectcreate rct2_text __text ${CMAKE_CURRENT_SOURCE_DIR}/build/openrct2_text -sectcreate rct2_data __data ${CMAKE_CURRENT_SOURCE_DIR}/build/openrct2_data -segaddr rct2_data 0x8a4000 -segprot rct2_data rwx rwx -segaddr rct2_text 0x401000 -segprot rct2_text rwx rwx -fno-pie -read_only_relocs suppress") endif (APPLE) set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS}) endif (UNIX) @@ -104,6 +104,24 @@ if (APPLE) TARGET_LINK_LIBRARIES(${PROJECT} ${ICONV_LIBRARIES}) endif (APPLE) +# handle creating the rct2 text and data files on OS X +if (APPLE) + add_custom_command( + OUTPUT openrct2_text + COMMAND dd if=${CMAKE_CURRENT_SOURCE_DIR}/openrct2.exe of=${CMAKE_BINARY_DIR}/openrct2_text bs=4096 skip=1 count=1187 + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/openrct2.exe + ) + add_custom_command( + OUTPUT openrct2_data + COMMAND dd if=${CMAKE_CURRENT_SOURCE_DIR}/openrct2.exe of=${CMAKE_BINARY_DIR}/openrct2_data bs=4096 skip=1188 count=318 + COMMAND dd if=/dev/zero of=${CMAKE_BINARY_DIR}/openrct2_data bs=4096 seek=318 count=2630 conv=notrunc + COMMAND dd if=${CMAKE_CURRENT_SOURCE_DIR}/openrct2.exe of=${CMAKE_BINARY_DIR}/openrct2_data bs=4096 skip=1506 seek=2948 count=1 conv=notrunc + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/openrct2.exe + ) + add_custom_target(segfiles DEPENDS openrct2_text openrct2_data) + add_dependencies(${PROJECT} segfiles) +endif (APPLE) + # install into ${CMAKE_INSTALL_PREFIX}/bin/ #install (TARGETS ${PROJECT} DESTINATION bin) diff --git a/src/network/network.h b/src/network/network.h index 56260ce5f2..3eefa4f923 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -90,6 +90,12 @@ extern "C" { #define ioctlsocket ioctl #endif // _WIN32 +// Fixes issues on OS X +#if defined(_RCT2_H_) && !defined(_MSC_VER) +// use similar struct packing as MSVC for our structs +#pragma pack(1) +#endif + #ifdef __cplusplus #include diff --git a/src/openrct2.c b/src/openrct2.c index 7a8c9c0959..74fd4848f5 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__)) -//unsigned char __attribute__((section ("rct2_text,__text"))) gTextSegment[0x004A3000]; -//unsigned char __attribute__((section ("rct2_data,__data"))) gDataSegment[0x01429000 - 0x8a4000]; +#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,8 +471,8 @@ 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__)) - /*#define RDATA_OFFSET 0x004A4000 +#if defined(__unix__) + #define RDATA_OFFSET 0x004A4000 #define DATASEG_OFFSET 0x005E2000 const char *exepath = "openrct2.exe"; @@ -551,23 +551,22 @@ static bool openrct2_setup_rct2_segment() 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 - - void* asdf = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_SHARED, 0, 0); - if (asdf != (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); + gDataSegment = mmap((void *)0x8a4000, len, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_SHARED, 0, 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); } len = 0x004A3000; // section: text - void* ffaa = mmap((void *)(0x401000), len, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE, gExeFd, 0x1000); - if (ffaa != (void *)(0x401000)) + gTextSegment = mmap((void *)(0x401000), len, PROT_EXEC | PROT_WRITE | PROT_READ, MAP_FIXED | MAP_PRIVATE, gExeFd, 0x1000); + if (gTextSegment != (void *)(0x401000)) { - log_fatal("mmap failed to get required offset for text segment! got %p, expected %p, errno = %d", gTextSegment, (void *)(0x401000), errno); - exit(1); + log_fatal("mmap failed to get required offset for text segment! got %p, expected %p, errno = %d", gTextSegment, (void *)(0x401000), errno); + exit(1); } - void *fbase = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE | MAP_FILE, gExeFd, 0); + void *fbase = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, gExeFd, 0); err = errno; log_warning("mmapped file to %p", fbase); if (fbase == MAP_FAILED) @@ -585,8 +584,8 @@ 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 @@ -610,8 +609,32 @@ static bool openrct2_setup_rct2_segment() static bool openrct2_release_rct2_segment() { bool result = true; -#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) -#endif // 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); + if (err != 0) + { + err = errno; + log_error("Failed to unmap data segment! errno = %d", err); + result = false; + } + len = 0x004A3000; + err = munmap(gTextSegment, len); + if (err != 0) + { + err = errno; + log_error("Failed to unmap text segment! errno = %d", err); + result = false; + } + err = close(gExeFd); + if (err != 0) + { + err = errno; + log_error("Failed to close file! errno = %d", err); + result = false; + } +#endif // defined(__unix__) return result; }