From 072db27968e14ca534f82a991e903d4f7d8ca18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Wed, 16 Dec 2015 01:28:56 +0100 Subject: [PATCH 1/2] add vanilla script --- distribution/linux/ld_script.xc | 209 ++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 distribution/linux/ld_script.xc diff --git a/distribution/linux/ld_script.xc b/distribution/linux/ld_script.xc new file mode 100644 index 0000000000..0a9741d505 --- /dev/null +++ b/distribution/linux/ld_script.xc @@ -0,0 +1,209 @@ +/* Script for -z combreloc: combine and sort reloc sections */ +/* Copyright (C) 2014 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("elf32-i386", "elf32-i386", + "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) +SEARCH_DIR("/usr/i386-unknown-linux-gnu/lib32"); SEARCH_DIR("/usr/x86_64-unknown-linux-gnu/lib32"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/usr/i386-unknown-linux-gnu/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + *(.rel.ifunc) + } + .rel.plt : + { + *(.rel.plt) + PROVIDE_HIDDEN (__rel_iplt_start = .); + *(.rel.iplt) + PROVIDE_HIDDEN (__rel_iplt_end = .); + } + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table + .gcc_except_table.*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges + .exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 32 / 8 : 1); + } + . = ALIGN(32 / 8); + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(32 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } +} From 7d132d8fe15bfb5a05f3a37fb846856fdb480853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Janiszewski?= Date: Wed, 16 Dec 2015 01:30:11 +0100 Subject: [PATCH 2/2] Extract and embed sections into binary itself Fixed some CMakeLists.txt problems, made another target for converting section images into something palatable by ld, modified the linker script to place these ssection at predefined VMAs and updated openrct2.c with new checks. --- CMakeLists.txt | 59 ++++++++++++---- distribution/linux/ld_script.xc | 7 +- src/openrct2.c | 115 ++++++-------------------------- src/openrct2.h | 2 +- 4 files changed, 72 insertions(+), 111 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b716af28d..cc97de3da1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,13 +32,6 @@ INCLUDE(FindPkgConfig) option(DISABLE_HTTP_TWITCH "Disable HTTP and Twitch support.") if (DISABLE_HTTP_TWITCH) add_definitions(-DDISABLE_HTTP -DDISABLE_TWITCH) -else (DISABLE_HTTP_TWITCH) - PKG_CHECK_MODULES(LIBCURL REQUIRED libcurl) - PKG_CHECK_MODULES(JANSSON REQUIRED jansson) - SET(HTTPLIBS ${LIBCURL_LIBRARIES} ${JANSSON_LIBRARIES}) - if (WIN32) - SET(HTTPLIBS ${HTTPLIBS} ssl crypto winmm.lib ws2_32) - endif (WIN32) endif (DISABLE_HTTP_TWITCH) option(DISABLE_NETWORK "Disable multiplayer functionality. Mainly for testing.") @@ -64,15 +57,21 @@ if (UNIX) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -std=gnu99 -fno-omit-frame-pointer -fno-pie") 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 ${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) # find and include SDL2 PKG_CHECK_MODULES(SDL2 REQUIRED sdl2 SDL2_ttf) +if (NOT DISABLE_HTTP_TWITCH) + PKG_CHECK_MODULES(LIBCURL REQUIRED libcurl) + PKG_CHECK_MODULES(JANSSON REQUIRED jansson) + SET(HTTPLIBS ${LIBCURL_LIBRARIES} ${JANSSON_LIBRARIES}) + if (WIN32) + SET(HTTPLIBS ${HTTPLIBS} ssl crypto winmm.lib ws2_32) + endif (WIN32) +endif (NOT DISABLE_HTTP_TWITCH) + # speex v1.1.15 is supplied in our zipped library, but distributions provide # updated version, with required functions extracted out to libspeexdsp. # This largely takes care of the problem @@ -110,8 +109,10 @@ if (APPLE) TARGET_LINK_LIBRARIES(${PROJECT} ${ICONV_LIBRARIES}) endif (APPLE) -# handle creating the rct2 text and data files on OS X -if (APPLE) +# Handle creating the rct2 text and data files on OS X and Linux +# See details in src/openrct2.c:openrct2_setup_rct2_segment for how the values +# were derived. +if (UNIX) 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 @@ -126,7 +127,37 @@ if (APPLE) ) add_custom_target(segfiles DEPENDS openrct2_text openrct2_data) add_dependencies(${PROJECT} segfiles) -endif (APPLE) + if (APPLE) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_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") + else (APPLE) + # For Linux we have to use objcopy to wrap regular binaries into a linkable + # format. We use specific section names which are then referenced in a + # bespoke linker script so they can be placed at predefined VMAs. + add_custom_command( + OUTPUT openrct2_text_section.o + COMMAND objcopy --input binary --output elf32-i386 --binary-architecture i386 openrct2_text openrct2_text_section.o --rename-section .data=.rct2_text,contents,alloc,load,readonly,code + DEPENDS segfiles + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + add_custom_command( + OUTPUT openrct2_data_section.o + COMMAND objcopy --input binary --output elf32-i386 --binary-architecture i386 openrct2_data openrct2_data_section.o --rename-section .data=.rct2_data,contents,alloc,load,readonly,data + DEPENDS segfiles + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + ) + add_custom_target(linkable_sections DEPENDS openrct2_text_section.o openrct2_data_section.o) + add_dependencies(${PROJECT} linkable_sections) + SET_SOURCE_FILES_PROPERTIES( + openrct2_text_section.o openrct2_data_section.o + PROPERTIES + EXTERNAL_OBJECT true + GENERATED true + ) + # can't use GLOB here, as the files don't exist yet at cmake-time + list(APPEND RCT2_SECTIONS "${CMAKE_BINARY_DIR}/openrct2_data_section.o" "${CMAKE_BINARY_DIR}/openrct2_text_section.o") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-T,${CMAKE_CURRENT_SOURCE_DIR}/distribution/linux/ld_script.xc") + endif (APPLE) +endif (UNIX) # install into ${CMAKE_INSTALL_PREFIX}/bin/ #install (TARGETS ${PROJECT} DESTINATION bin) @@ -134,4 +165,4 @@ endif (APPLE) # libopenrct2.dll -> openrct2.dll set_target_properties(${PROJECT} PROPERTIES PREFIX "") -TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES} ${ORCTLIBS_LIB} ${JANSSON_LIBRARIES} ${HTTPLIBS} ${NETWORKLIBS} ${SPEEX_LIBRARIES} ${DLLIB}) +TARGET_LINK_LIBRARIES(${PROJECT} ${SDL2_LIBRARIES} ${ORCTLIBS_LIB} ${HTTPLIBS} ${NETWORKLIBS} ${SPEEX_LIBRARIES} ${DLLIB} ${RCT2_SECTIONS}) diff --git a/distribution/linux/ld_script.xc b/distribution/linux/ld_script.xc index 0a9741d505..5e3b3be7be 100644 --- a/distribution/linux/ld_script.xc +++ b/distribution/linux/ld_script.xc @@ -1,3 +1,4 @@ +/* This script is based on elf_i386.xc with modifications for OpenRCT2 */ /* Script for -z combreloc: combine and sort reloc sections */ /* Copyright (C) 2014 Free Software Foundation, Inc. Copying and distribution of this script, with or without modification, @@ -11,7 +12,8 @@ SEARCH_DIR("/usr/i386-unknown-linux-gnu/lib32"); SEARCH_DIR("/usr/x86_64-unknown SECTIONS { /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x08048000)); . = SEGMENT_START("text-segment", 0x08048000) + SIZEOF_HEADERS; + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x010000)); . = SEGMENT_START("text-segment", 0x010000) + SIZEOF_HEADERS; + .interp : { *(.interp) } .note.gnu.build-id : { *(.note.gnu.build-id) } .hash : { *(.hash) } @@ -49,6 +51,8 @@ SECTIONS KEEP (*(SORT_NONE(.init))) } .plt : { *(.plt) *(.iplt) } + .rct2_text 0x401000 : { *(.rct2_text) } + .rct2_data : { *(.rct2_data) } .text : { *(.text.unlikely .text.*_unlikely .text.unlikely.*) @@ -206,4 +210,5 @@ SECTIONS .debug_macro 0 : { *(.debug_macro) } .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } + } diff --git a/src/openrct2.c b/src/openrct2.c index c35dfb2d17..6b1919d082 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -59,12 +59,6 @@ bool gOpenRCT2Headless = false; bool gOpenRCT2ShowChangelog; -#if defined(__unix__) -void *gDataSegment; -void *gTextSegment; -int gExeFd; -#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; @@ -73,7 +67,6 @@ static struct { sint16 x, y, z; } _spritelocations1[MAX_SPRITES], _spritelocatio static void openrct2_loop(); static bool openrct2_setup_rct2_segment(); -static bool openrct2_release_rct2_segment(); static void openrct2_setup_rct2_hooks(); void openrct2_write_full_version_info(utf8 *buffer, size_t bufferSize) @@ -317,7 +310,6 @@ void openrct2_dispose() network_close(); http_dispose(); language_close_all(); - openrct2_release_rct2_segment(); platform_free(); } @@ -469,19 +461,12 @@ void openrct2_reset_object_tween_locations() */ 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 + // OpenRCT2 on Linux and OS X is wired to have the original Windows PE sections loaded // necessary. Windows does not need to do this as OpenRCT2 runs as a DLL loaded from the Windows PE. #if defined(__unix__) #define RDATA_OFFSET 0x004A4000 #define DATASEG_OFFSET 0x005E2000 - const char *exepath = "openrct2.exe"; - gExeFd = open(exepath, O_RDONLY); - if (gExeFd < 0) { - log_fatal("failed to open %s, errno = %d", exepath, errno); - exit(1); - } - // Using PE-bear I was able to figure out all the needed addresses to be filled. // There are three sections to be loaded: .rdata, .data and .text, plus another // one to be mapped: DATASEG. @@ -504,10 +489,9 @@ static bool openrct2_setup_rct2_segment() // 0x9a6000 + 0xA81C3C = 0x1427C3C, which after alignment to page size becomes // 0x1428000, which can be seen as next section, DATASEG // - // Since mmap does not provide a way to create a mapping with virtual size, - // I resorted to creating a one large map for data and memcpy'ing data where - // required. - // Another section is needed for .text, as it requires PROT_EXEC flag. + // The data is now loaded into memory with a linker script, which proves to + // be more reliable, as mallocs that happen before we reach segment setup + // could have already taken the space we need. // TODO: UGLY, UGLY HACK! off_t file_size = 6750208; @@ -517,7 +501,7 @@ static bool openrct2_setup_rct2_segment() int numPages = (len + pageSize - 1) / pageSize; unsigned char *dummy = malloc(numPages); int err = mincore((void *)0x8a4000, len, dummy); - bool pagesDirty = false; + bool pagesMissing = false; if (err != 0) { err = errno; @@ -525,65 +509,41 @@ static bool openrct2_setup_rct2_segment() // On Linux ENOMEM means all requested range is unmapped if (err != ENOMEM) { - pagesDirty = true; + pagesMissing = true; perror("mincore"); } #else - pagesDirty = true; + pagesMissing = true; perror("mincore"); #endif // __linux__ } else { - log_warning("mincore ok"); for (int i = 0; i < numPages; i++) { - if (dummy[i] != 0) + if (dummy[i] != 1) { - pagesDirty = true; + pagesMissing = 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]); + log_warning("required page %p - %p is not in memory!", start, end); } } } free(dummy); - if (pagesDirty) + if (pagesMissing) { - 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."); + log_error("At least one of required pages was not found in memory. This can cause segfaults later on."); } - // section: rw data - 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); - } - - len = 0x004A3000; // section: text - 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); - } - - 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) - { - log_fatal("mmap failed to get required offset! got %p, errno = %d", fbase, err); - exit(1); - } - // .rdata and real part of .data - // 0x9e2000 - 0x8a4000 = 0x13e000 - memcpy(gDataSegment, fbase + RDATA_OFFSET, 0x13e000); - // 0x8a4000 + 0xb84000 = 0x1428000 aka DATASEG - memcpy(gDataSegment + 0xB84000, fbase + DATASEG_OFFSET, 0x1000); - err = munmap(fbase, file_size); + err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_WRITE | PROT_EXEC); if (err != 0) { - err = errno; - log_error("Failed to unmap file! errno = %d", err); + perror("mprotect"); + } + // section: rw data + err = mprotect((void *)0x8a4000, 0x01429000 - 0x8a4000, PROT_READ | PROT_WRITE); + if (err != 0) + { + perror("mprotect"); } #endif // defined(__unix__) @@ -603,41 +563,6 @@ static bool openrct2_setup_rct2_segment() return true; } -/** - * Releases segments created with @ref openrct2_setup_rct2_segment, if any. - */ -static bool openrct2_release_rct2_segment() -{ - bool result = true; -#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; -} - /** * Setup hooks to allow RCT2 to call OpenRCT2 functions instead. */ diff --git a/src/openrct2.h b/src/openrct2.h index 4642985872..6d9853ad95 100644 --- a/src/openrct2.h +++ b/src/openrct2.h @@ -44,4 +44,4 @@ void openrct2_dispose(); void openrct2_finish(); void openrct2_reset_object_tween_locations(); -#endif \ No newline at end of file +#endif