diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2bb0da725b..a29aab1011 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,10 @@ add_definitions(-DOPENRCT2_COMMIT_SHA1_SHORT="${OPENRCT2_COMMIT_SHA1_SHORT}")
INCLUDE(FindPkgConfig)
+if (APPLE)
+ set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/opt/openssl/lib/pkgconfig")
+endif (APPLE)
+
# Options
option(DISABLE_HTTP_TWITCH "Disable HTTP and Twitch support.")
@@ -75,12 +79,17 @@ option(STATIC "Create a static build.")
option(FORCE64 "Force native (x86-64) build. Do not use, for experimental purposes only.")
option(DISABLE_OPENGL "Disable OpenGL support.")
option(DISABLE_RCT2 "WIP: Try building without using code and data segments from vanilla.")
+option(USE_MMAP "Use mmap to try loading rct2's data segment into memory.")
if (FORCE64)
set(TARGET_M "-m64")
set(OBJ_FORMAT "elf64-x86-64")
set(LINKER_SCRIPT "ld_script_x86_64.xc")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast")
+ if ((APPLE OR WIN32) AND NOT USE_MMAP)
+ message(WARNING "Building such configuration won't work. Enabling USE_MMAP.")
+ set(USE_MMAP ON)
+ endif()
else ()
set(TARGET_M "-m32")
set(OBJ_FORMAT "elf32-i386")
@@ -94,6 +103,10 @@ else (DISABLE_OPENGL)
add_definitions(-DOPENGL_NO_LINK)
endif (DISABLE_OPENGL)
+if (USE_MMAP)
+ add_definitions(-DUSE_MMAP)
+endif (USE_MMAP)
+
if (DISABLE_NETWORK)
add_definitions(-DDISABLE_NETWORK)
else (DISABLE_NETWORK)
@@ -142,35 +155,40 @@ if (UNIX)
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/openrct2.exe
)
add_custom_target(segfiles DEPENDS openrct2_text openrct2_data)
- 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 -segaddr __TEXT 0x2000000 -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 ${OBJ_FORMAT} --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 ${OBJ_FORMAT} --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)
- 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
- set(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/${LINKER_SCRIPT}\"")
- endif (APPLE)
+ if (NOT USE_MMAP)
+ 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 -segaddr __TEXT 0x2000000 -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 ${OBJ_FORMAT} --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 ${OBJ_FORMAT} --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)
+ 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
+ set(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/${LINKER_SCRIPT}\"")
+ endif (APPLE)
+ endif (NOT USE_MMAP)
+elseif (USE_MMAP)
+ # No dd here, can't extract data segment
+ message(WARNING "Sorry, your platform is not supported, you have to extract data segment manually")
endif (UNIX)
set(DEBUG_LEVEL 0 CACHE STRING "Select debug level for compilation. Use value in range 0–3.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG=${DEBUG_LEVEL}")
@@ -226,6 +244,10 @@ if (NOT DISABLE_OPENGL)
if (WIN32)
# Curl depends on openssl and ws2 in mingw builds, but is not wired up in pkg-config
set(GLLIBS opengl32)
+ elseif (APPLE)
+ # GL doesn't work nicely with macOS, while find_package doesn't work with multiarch on Ubuntu.
+ find_package(OpenGL REQUIRED)
+ set(GLLIBS ${OPENGL_LIBRARY})
else (WIN32)
PKG_CHECK_MODULES(GL REQUIRED gl)
set(GLLIBS ${GL_LIBRARIES})
@@ -252,7 +274,7 @@ if (UNIX)
set(DLLIB dl)
endif (UNIX)
-INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS} ${LIBCURL_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS} ${SPEEX_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${BREAKPAD_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS} ${LIBCURL_INCLUDE_DIRS} ${JANSSON_INCLUDE_DIRS} ${SPEEX_INCLUDE_DIRS} ${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} ${BREAKPAD_INCLUDE_DIR} ${SSL_INCLUDE_DIRS})
LINK_DIRECTORIES(${SDL2_LIBRARY_DIRS} ${JANSSON_LIBRARY_DIRS} ${LIBCURL_LIBRARY_DIRS} ${PNG_LIBRARY_DIRS} ${ZLIB_LIBRARY_DIRS} ${BREAKPAD_LIBRARY_DIR} ${SSL_LIBRARY_DIRS})
@@ -264,7 +286,11 @@ endif (NOT DISABLE_RCT2)
if (WIN32)
# build as library for now, replace with add_executable
- add_library(${PROJECT} SHARED ${ORCT2_SOURCES} ${SPEEX_SOURCES})
+ if (USE_MMAP)
+ add_executable(${PROJECT} ${ORCT2_SOURCES} ${SPEEX_SOURCES})
+ else ()
+ add_library(${PROJECT} SHARED ${ORCT2_SOURCES} ${SPEEX_SOURCES})
+ endif ()
else (WIN32)
add_executable(${PROJECT} ${ORCT2_SOURCES} ${ORCT2_MM_SOURCES} ${RCT2_SECTIONS})
add_dependencies(${PROJECT} segfiles)
diff --git a/openrct2.vcxproj b/openrct2.vcxproj
index cb47bc6867..1c82ce90d8 100644
--- a/openrct2.vcxproj
+++ b/openrct2.vcxproj
@@ -650,7 +650,7 @@
Level3
Disabled
true
- $(OpenRCT2_DEFINES);DEBUG;OPENGL_NO_LINK;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
+ USE_MMAP;$(OpenRCT2_DEFINES);DEBUG;OPENGL_NO_LINK;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;_WINSOCK_DEPRECATED_NO_WARNINGS;%(PreprocessorDefinitions)
MultiThreaded
true
$(IntDir)\%(RelativeDir)
@@ -677,7 +677,7 @@
4013
false
- $(OpenRCT2_DEFINES);OPENGL_NO_LINK;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;%(PreprocessorDefinitions)
+ USE_MMAP;$(OpenRCT2_DEFINES);OPENGL_NO_LINK;_CRT_SECURE_NO_WARNINGS;_USE_MATH_DEFINES;CURL_STATICLIB;SDL_MAIN_HANDLED;%(PreprocessorDefinitions)
$(IntDir)\%(RelativeDir)
true
Speed
diff --git a/src/addresses.h b/src/addresses.h
index 98b02c8d69..658859b0ad 100644
--- a/src/addresses.h
+++ b/src/addresses.h
@@ -23,8 +23,14 @@
#pragma warning(disable : 4731)
#endif
-#define RCT2_ADDRESS(address, type) ((type*)(address))
-#define RCT2_GLOBAL(address, type) (*((type*)(address)))
+#ifdef USE_MMAP
+ #define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x200000000)
+#else
+ #define GOOD_PLACE_FOR_DATA_SEGMENT ((uintptr_t)0x8a4000)
+#endif
+
+#define RCT2_ADDRESS(address, type) ((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8a4000 + (address)))
+#define RCT2_GLOBAL(address, type) (*((type*)(GOOD_PLACE_FOR_DATA_SEGMENT - 0x8a4000 + (address))))
#pragma region Memory locations
diff --git a/src/openrct2.c b/src/openrct2.c
index f450fba13f..aa48ee58a9 100644
--- a/src/openrct2.c
+++ b/src/openrct2.c
@@ -40,16 +40,18 @@
#include "version.h"
#include "world/mapgen.h"
-#if defined(__unix__)
+#if defined(__unix__) || defined(__MACOSX__)
#include
#include
#include
#include
#include
#include
-#endif // defined(__unix__)
+#endif // defined(__unix__) || defined(__MACOSX__)
int gExitCode;
+int fdData;
+char *segments = (void *)(GOOD_PLACE_FOR_DATA_SEGMENT);
int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE;
utf8 gOpenRCT2StartupActionPath[512] = { 0 };
@@ -350,6 +352,10 @@ void openrct2_dispose()
#ifndef DISABLE_NETWORK
EVP_MD_CTX_destroy(gHashCTX);
#endif // DISABLE_NETWORK
+#if defined(USE_MMAP) && (defined(__unix__) || defined(__MACOSX__))
+ munmap(segments, 12079104);
+ close(fdData);
+#endif
platform_free();
}
@@ -499,7 +505,9 @@ bool openrct2_setup_rct2_segment()
{
// OpenRCT2 on Linux and macOS 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__)
+ int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB
+ int err = 0;
+#if defined(USE_MMAP) && (defined(__unix__) || defined(__MACOSX__))
#define RDATA_OFFSET 0x004A4000
#define DATASEG_OFFSET 0x005E2000
@@ -532,11 +540,27 @@ bool openrct2_setup_rct2_segment()
// TODO: UGLY, UGLY HACK!
//off_t file_size = 6750208;
- int len = 0x01429000 - 0x8a4000; // 0xB85000, 12079104 bytes or around 11.5MB
+ fdData = open("openrct2_data", O_RDONLY);
+ if (fdData < 0)
+ {
+ log_fatal("failed to load openrct2_data");
+ exit(1);
+ }
+ log_warning("%p", GOOD_PLACE_FOR_DATA_SEGMENT);
+ segments = mmap((void *)(GOOD_PLACE_FOR_DATA_SEGMENT), len, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE, fdData, 0);
+ log_warning("%p", segments);
+ if ((uintptr_t)segments != GOOD_PLACE_FOR_DATA_SEGMENT) {
+ perror("mmap");
+ return false;
+ }
+#endif // defined(USE_MMAP) && (defined(__unix__) || defined(__MACOSX__))
+
+#if defined(__unix__)
int pageSize = getpagesize();
int numPages = (len + pageSize - 1) / pageSize;
unsigned char *dummy = malloc(numPages);
- int err = mincore((void *)0x8a4000, len, dummy);
+
+ err = mincore((void *)0x8a4000, len, dummy);
bool pagesMissing = false;
if (err != 0)
{
@@ -569,12 +593,14 @@ bool openrct2_setup_rct2_segment()
{
log_error("At least one of required pages was not found in memory. This can cause segfaults later on.");
}
+#if !defined(USE_MMAP)
// section: text
err = mprotect((void *)0x401000, 0x8a4000 - 0x401000, PROT_READ | PROT_EXEC);
if (err != 0)
{
perror("mprotect");
}
+#endif // !defined(USE_MMAP)
// section: rw data
err = mprotect((void *)0x8a4000, 0x01429000 - 0x8a4000, PROT_READ | PROT_WRITE);
if (err != 0)
@@ -583,12 +609,30 @@ bool openrct2_setup_rct2_segment()
}
#endif // defined(__unix__)
-#if !defined(NO_RCT2) || !defined(__WINDOWS__)
+#if defined(USE_MMAP) && defined(__WINDOWS__)
+ segments = VirtualAlloc((void *)(GOOD_PLACE_FOR_DATA_SEGMENT), len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+ if ((uintptr_t)segments != GOOD_PLACE_FOR_DATA_SEGMENT) {
+ log_error("VirtualAlloc, segments = %p, GetLastError = 0x%x", segments, GetLastError());
+ return false;
+ }
+ SDL_RWops * rw = SDL_RWFromFile("openrct2_data", "rb");
+ if (rw == NULL)
+ {
+ log_error("failed to load file");
+ return false;
+ }
+ if (SDL_RWread(rw, segments, len, 1) != 1) {
+ log_error("Unable to read chunk header!");
+ return false;
+ }
+ SDL_RWclose(rw);
+#endif // defined(USE_MMAP) && defined(__WINDOWS__)
+
// 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
// calls, which can be changed by windows/wine loader.
- const uint32 c1 = sawyercoding_calculate_checksum((void *)0x009A6000, 0x009E0000 - 0x009A6000);
- const uint32 c2 = sawyercoding_calculate_checksum((void *)0x01428000, 0x014282BC - 0x01428000);
+ const uint32 c1 = sawyercoding_calculate_checksum((const uint8*)(segments + (uintptr_t)(0x009A6000 - 0x8a4000)), 0x009E0000 - 0x009A6000);
+ const uint32 c2 = sawyercoding_calculate_checksum((const uint8*)(segments + (uintptr_t)(0x01428000 - 0x8a4000)), 0x014282BC - 0x01428000);
const uint32 exp_c1 = 10114815;
const uint32 exp_c2 = 23564;
if (c1 != exp_c1 || c2 != exp_c2) {
@@ -596,7 +640,6 @@ bool openrct2_setup_rct2_segment()
log_warning("c2 = %u, expected %u, match %d", c2, exp_c2, c2 == exp_c2);
return false;
}
-#endif
return true;
}
diff --git a/src/platform/windows.c b/src/platform/windows.c
index c19d2d394c..8ab8449a60 100644
--- a/src/platform/windows.c
+++ b/src/platform/windows.c
@@ -59,7 +59,7 @@ static HMODULE _dllModule = NULL;
/**
* Windows entry point to OpenRCT2 with a console window using a traditional C main function.
*/
-int main(char *argv[], int argc)
+int main(int argc, char *argv[])
{
HINSTANCE hInstance = GetModuleHandle(NULL);
_dllModule = hInstance;
diff --git a/src/ride/track_paint.c b/src/ride/track_paint.c
index 638e03c4f6..d8c913da69 100644
--- a/src/ride/track_paint.c
+++ b/src/ride/track_paint.c
@@ -1297,6 +1297,7 @@ void track_paint(uint8 direction, int height, rct_map_element *mapElement)
}
}
else {
+#ifndef NO_RCT2
TRACK_PAINT_FUNCTION **trackTypeList = (TRACK_PAINT_FUNCTION**)RideTypeTrackPaintFunctionsOld[rideType];
uint32 *trackDirectionList = (uint32*)trackTypeList[trackType];
@@ -1311,6 +1312,7 @@ void track_paint(uint8 direction, int height, rct_map_element *mapElement)
rideIndex * sizeof(rct_ride),
trackSequence
);
+#endif
}
}