VVVVVV icon indicating copy to clipboard operation
VVVVVV copied to clipboard

suggestion: build without PIE on macOS, if possible?

Open iliana opened this issue 2 years ago • 10 comments

The Linux and Windows builds of VVVVVV are not position-independent executables because the compilers used for these releases do not enable PIE by default. This allows autosplitters on Linux and Windows to hardcode relevant memory addresses for different versions (or since 64be99d496186fa28ccff4b260c87b733ecb1ac8, run the program with -addresses to prevent needing to hardcode future versions).

macOS's compiler enables PIE by default, thus enabling address space layout randomization, which resulted in me making some wild implementation-specific memory searching code. -addresses won't address the issue for macOS because the addresses will be different every time the program starts.

A flag to disable PIE for Linux builds may help in the future as well; if the build environment ends up being updated from CentOS 7, generally any newer Linux distro will enable PIE by default.

(I am posting this issue in the hopes that someone who understands CMake and Clang options more than me will consider updating the build scripts; I am attempting to come up with a solution on my own as well, though.)

iliana avatar Feb 20 '23 08:02 iliana

This sounds reasonable to add to the CMakeLists.txt. Should be as simple as something like a -fno-pie or similar to the compiler, but I haven't checked yet.

InfoTeddy avatar Feb 20 '23 09:02 InfoTeddy

Preliminary searching suggests both GCC and Clang support -no-pie, but it seems to not exist in all versions of those compilers. Not sure where the version cutoff is. Not sure what the equivalent flag is for MSVC.

InfoTeddy avatar Feb 20 '23 09:02 InfoTeddy

I tried adding a long pile of no-pie flags and still couldn't get macOS to build me a version without PIE.

diff --git a/desktop_version/CMakeLists.txt b/desktop_version/CMakeLists.txt
index 7f181ef..2615b15 100644
--- a/desktop_version/CMakeLists.txt
+++ b/desktop_version/CMakeLists.txt
@@ -439,6 +439,11 @@ else()
     endif()
 endif()

+if(NOT MSVC)
+    target_compile_options(VVVVVV PRIVATE -no-pie -fno-pie -fno-PIE -Wl,-no_pie)
+    target_link_libraries(VVVVVV -no-pie -fno-pie)
+endif()
+
 # Yes, more Apple Crap
 if(APPLE)
     find_library(FOUNDATION NAMES Foundation)

Some particularly damning compiler spew (thanks, lld!):

ld: warning: -no_pie is deprecated when targeting new OS versions
ld: warning: -no_pie ignored for arm64
$ otool -hv VVVVVV 
VVVVVV:
Mach header
      magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64    ARM64        ALL  0x00     EXECUTE    24       2520   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

So maybe there is not really a good solution here in the long run.

iliana avatar Feb 21 '23 18:02 iliana

Yeah, it seems to me that macOS is strictly enforcing PIE in the future for whatever reason.

InfoTeddy avatar Feb 21 '23 19:02 InfoTeddy

An alternative, possibly-silly suggestion to help out future autosplitters on platforms where memory scanning is inevitable, and thus the -addresses option is not as useful, might be to add a static string to the start of some objects, e.g.:

diff --git a/desktop_version/src/Game.h b/desktop_version/src/Game.h
index 6dc2517..904b19e 100644
--- a/desktop_version/src/Game.h
+++ b/desktop_version/src/Game.h
@@ -133,6 +133,8 @@ struct CustomLevelStat
 class Game
 {
 public:
+    char magic[16];
+
     void init(void);
 
 
diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp
index 847044d..e124392 100644
--- a/desktop_version/src/Game.cpp
+++ b/desktop_version/src/Game.cpp
@@ -158,6 +158,8 @@ end:
 
 void Game::init(void)
 {
+    SDL_strlcpy(magic, "[vVvVvV]game", 16);
+
     roomx = 0;
     roomy = 0;
     prevroomx = 0;

It's likely only one marker string is necessary because you can rely on relative offsets based on -addresses for the various globals.

If this seems like an acceptable I'll make sure that memory string is actually unique and open a PR.

iliana avatar Feb 21 '23 19:02 iliana

Yes, this is acceptable. It's something I was considering too. Though, use sizeof(magic) instead of duplicating the length of the array.

InfoTeddy avatar Feb 21 '23 19:02 InfoTeddy

oh, the commit message closed the issue anyway. oops

iliana avatar Feb 21 '23 20:02 iliana

lmao

InfoTeddy avatar Feb 21 '23 20:02 InfoTeddy

Here are some things I found that may help. I do not have macOS, so I can't test any of these.

According to this 2-year-old blog post, LLDB will disable ASLR by default. How it does this I do not know. Might be worth looking into.

In the latest CMake version, there is a POSITION_INDEPENDENT_CODE property as well as a CheckPIESupported function. Maybe these can be used to definitively conclude if macOS allows disabling PIE or not.

InfoTeddy avatar Mar 19 '23 06:03 InfoTeddy

lldb starts the application via posix_spawn with the undocumented _POSIX_SPAWN_DISABLE_ASLR flag (0x0100) set via posix_spawnattr_setflags. It may be safest for vitellary to do that itself. Spawning VVVVVV as a subprocess might also avoid problems with Linux distributions that enable restricted ptrace.

leo60228 avatar Sep 08 '23 01:09 leo60228