Implement macOS (Intel) support

This commit is contained in:
Julio C. Rocha authored and Dan Turner committed 2026-09-30 10:09:35 +01:00
1 parent 0e8c2ce213
commit ae1884cc05
15 files changed
+328 -35

No files matched your search

+114 -9
View File
@@ -25,11 +25,26 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
# name as an inherited one — CCTVRecord's `pad` — see docs/internals.md.)
# An explicit -DCMAKE_C_COMPILER=... always wins.
if(NOT DEFINED CMAKE_C_COMPILER)
find_program(_GE007_GCC NAMES gcc)
if(CMAKE_HOST_APPLE)
# Homebrew installs real GNU GCC with a version suffix; /usr/bin/gcc is
# Apple Clang and does not support the Plan 9 struct extensions required
# by the decomp's `inherits` pattern.
find_program(_GE007_GCC
NAMES gcc-16 gcc-15 gcc-14 gcc-13 gcc-12 gcc-11 gcc)
else()
find_program(_GE007_GCC NAMES gcc)
endif()
if(_GE007_GCC)
set(CMAKE_C_COMPILER "${_GE007_GCC}" CACHE FILEPATH "C compiler" FORCE)
get_filename_component(_GE007_GCC_DIR "${_GE007_GCC}" DIRECTORY)
find_program(_GE007_GXX NAMES g++ PATHS "${_GE007_GCC_DIR}" NO_DEFAULT_PATH)
if(CMAKE_HOST_APPLE)
find_program(_GE007_GXX
NAMES g++-16 g++-15 g++-14 g++-13 g++-12 g++-11 g++
PATHS "${_GE007_GCC_DIR}" NO_DEFAULT_PATH)
else()
find_program(_GE007_GXX NAMES g++
PATHS "${_GE007_GCC_DIR}" NO_DEFAULT_PATH)
endif()
if(_GE007_GXX)
set(CMAKE_CXX_COMPILER "${_GE007_GXX}" CACHE FILEPATH "CXX compiler" FORCE)
endif()
@@ -163,7 +178,18 @@ configure_file(
# the toolchain include dir from the compiler location (MinGW/MSYS2 layout:
# bin/../include) and generate an absolute-path include.
get_filename_component(_PORT_GCC_DIR "${CMAKE_C_COMPILER}" DIRECTORY)
get_filename_component(PORT_HOST_STRING_H "${_PORT_GCC_DIR}/../include/string.h" ABSOLUTE)
if(APPLE)
execute_process(
COMMAND xcrun --show-sdk-path
OUTPUT_VARIABLE _PORT_MACOS_SDK OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if(NOT _PORT_MACOS_SDK)
message(FATAL_ERROR "Cannot locate the macOS SDK; install the Xcode Command Line Tools")
endif()
set(PORT_HOST_STRING_H "${_PORT_MACOS_SDK}/usr/include/string.h")
else()
get_filename_component(PORT_HOST_STRING_H "${_PORT_GCC_DIR}/../include/string.h" ABSOLUTE)
endif()
configure_file(
"${CMAKE_SOURCE_DIR}/port/include/hoststring.h.in"
"${CMAKE_BINARY_DIR}/port/include/hoststring.h" @ONLY)
@@ -172,7 +198,11 @@ configure_file(
# the include path and shadows the system header; libstdc++'s <thread>/gthr
# headers in the fast3d C++ TUs need the real <sched.h> (cpu_set_t,
# sched_yield). Both MinGW and Linux keep <sched.h> at bin/../include.
get_filename_component(PORT_HOST_SCHED_H "${_PORT_GCC_DIR}/../include/sched.h" ABSOLUTE)
if(APPLE)
set(PORT_HOST_SCHED_H "${_PORT_MACOS_SDK}/usr/include/sched.h")
else()
get_filename_component(PORT_HOST_SCHED_H "${_PORT_GCC_DIR}/../include/sched.h" ABSOLUTE)
endif()
configure_file(
"${CMAKE_SOURCE_DIR}/port/include/hostsched.h.in"
"${CMAKE_BINARY_DIR}/port/include/hostsched.h" @ONLY)
@@ -182,7 +212,11 @@ configure_file(
# one C++ TU (fast3d): MinGW's own sec_api/stdlib_s.h does `#include
# <stdlib.h>`, which resolves to the N64 header via -I. The shim routes C++
# TUs to the host header by absolute path (same trick as hoststring.h).
get_filename_component(PORT_HOST_STDLIB_H "${_PORT_GCC_DIR}/../include/stdlib.h" ABSOLUTE)
if(APPLE)
set(PORT_HOST_STDLIB_H "${_PORT_MACOS_SDK}/usr/include/stdlib.h")
else()
get_filename_component(PORT_HOST_STDLIB_H "${_PORT_GCC_DIR}/../include/stdlib.h" ABSOLUTE)
endif()
configure_file(
"${CMAKE_SOURCE_DIR}/port/include/hoststdlib.h.in"
"${CMAKE_BINARY_DIR}/port/include/hoststdlib.h" @ONLY)
@@ -328,6 +362,13 @@ elseif(UNIX AND NOT APPLE)
# relocations are fine (unlike a 0x140000000 base, which needs mcmodel=large).
# This is the ELF analogue of the Windows build's fixed 0x140000000 base.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Ttext-segment=0x20000000")
elseif(APPLE)
# Mach-O executables normally reserve [0, 4 GiB) as __PAGEZERO. The port
# needs fixed mappings at 0x10000000 (ROM), 0x70000000 (s32-safe DRAM), and
# 0x80000000 (KSEG0 mirror), so retain null/low-pointer protection only up
# while leaving ample space before the first required mapping.
set(CMAKE_EXE_LINKER_FLAGS
"${CMAKE_EXE_LINKER_FLAGS} -Wl,-pagezero_size,0x10000")
endif()
# port/shim first: PC-only shadow headers (bondtypes.h, bondconstants.h,
@@ -342,6 +383,7 @@ include_directories(
"${CMAKE_SOURCE_DIR}/src/game"
"${CMAKE_SOURCE_DIR}/src/libultra"
"${CMAKE_SOURCE_DIR}/src/libultra/audio"
"${CMAKE_SOURCE_DIR}/src/libultra/gu"
"${CMAKE_SOURCE_DIR}/port/include"
"${CMAKE_BINARY_DIR}/port/include"
)
@@ -395,6 +437,8 @@ if(NOT EXTRA_LIBRARIES)
set(EXTRA_LIBRARIES dbghelp -static-libstdc++ pthread)
elseif(WIN32)
set(EXTRA_LIBRARIES dbghelp -static-libstdc++)
elseif(APPLE)
set(EXTRA_LIBRARIES stdc++ m pthread)
else()
set(EXTRA_LIBRARIES stdc++ m dl pthread)
endif()
@@ -414,14 +458,41 @@ file(GLOB_RECURSE SRC_FAST3D "${CMAKE_SOURCE_DIR}/port/fast3d/*.cpp"
# scripts/gen_romassets.py). Defines every obseg/ramrom/music label and the
# ge007.ld segment markers as 0x10000000 + rom_offset, so `&symbol` / romCopy()
# work once romdata.c maps the .z64 at 0x10000000.
set(SRC_ROMASSETS "${CMAKE_SOURCE_DIR}/port/src/romassets_${ASSET_REGION}.s")
if(NOT EXISTS ${SRC_ROMASSETS})
message(FATAL_ERROR "Missing ${SRC_ROMASSETS} — run: python3 scripts/gen_romassets.py ${ASSET_REGION}")
set(SRC_ROMASSETS_INPUT "${CMAKE_SOURCE_DIR}/port/src/romassets_${ASSET_REGION}.s")
if(NOT EXISTS ${SRC_ROMASSETS_INPUT})
message(FATAL_ERROR "Missing ${SRC_ROMASSETS_INPUT} — run: python3 scripts/gen_romassets.py ${ASSET_REGION}")
endif()
# Absolute symbols inside the reserved N64-DRAM region (port/src/dram.c):
# cfb_16 (replaces src/cfb.c) and _bssSegmentEnd (mempool start marker).
set(SRC_DRAM_SYMS "${CMAKE_SOURCE_DIR}/port/src/dram_syms.s")
set(SRC_DRAM_SYMS_INPUT "${CMAKE_SOURCE_DIR}/port/src/dram_syms.s")
if(APPLE)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
set(SRC_ROMASSETS "${CMAKE_BINARY_DIR}/port/src/romassets_${ASSET_REGION}_macho.s")
set(SRC_DRAM_SYMS "${CMAKE_BINARY_DIR}/port/src/dram_syms_macho.s")
add_custom_command(
OUTPUT "${SRC_ROMASSETS}"
COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
"${SRC_ROMASSETS_INPUT}" "${SRC_ROMASSETS}"
DEPENDS "${SRC_ROMASSETS_INPUT}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
VERBATIM)
add_custom_command(
OUTPUT "${SRC_DRAM_SYMS}"
COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
"${SRC_DRAM_SYMS_INPUT}" "${SRC_DRAM_SYMS}"
DEPENDS "${SRC_DRAM_SYMS_INPUT}"
"${CMAKE_SOURCE_DIR}/scripts/gen_macho_syms.py"
VERBATIM)
set_source_files_properties(${SRC_ROMASSETS} ${SRC_DRAM_SYMS}
PROPERTIES GENERATED TRUE)
else()
set(SRC_ROMASSETS "${SRC_ROMASSETS_INPUT}")
set(SRC_DRAM_SYMS "${SRC_DRAM_SYMS_INPUT}")
endif()
# Game code — compiled unmodified.
file(GLOB_RECURSE SRC_GAME "${CMAKE_SOURCE_DIR}/src/game/*.c")
@@ -452,6 +523,39 @@ file(GLOB SRC_LIBULTRARE_AUDIO "${CMAKE_SOURCE_DIR}/src/libultrare/audio/*.c")
# gu matrix helpers.
file(GLOB SRC_GU "${CMAKE_SOURCE_DIR}/src/libultra/gu/*.c")
# GCC for Darwin crashes while lowering the decomp's ELF-style
# `#pragma weak alias = target` directives. Compile generated copies with
# those directives removed, then provide their aliases in Mach-O assembly.
set(SRC_MACHO_ALIASES "")
if(APPLE)
set(_MACHO_GENERATED_SOURCES "")
set(_MACHO_WEAK_INPUTS
"${CMAKE_SOURCE_DIR}/src/game/lv.c"
"${CMAKE_SOURCE_DIR}/src/game/objective_status.c"
"${CMAKE_SOURCE_DIR}/src/game/spectrum.c"
"${CMAKE_SOURCE_DIR}/src/libultra/gu/sinf.c"
"${CMAKE_SOURCE_DIR}/src/libultra/gu/cosf.c")
foreach(_INPUT IN LISTS _MACHO_WEAK_INPUTS)
get_filename_component(_NAME "${_INPUT}" NAME)
set(_OUTPUT "${CMAKE_BINARY_DIR}/port/src/macho_${_NAME}")
add_custom_command(
OUTPUT "${_OUTPUT}"
COMMAND "${Python3_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/strip_weak_pragmas.py"
"${_INPUT}" "${_OUTPUT}"
DEPENDS "${_INPUT}" "${CMAKE_SOURCE_DIR}/scripts/strip_weak_pragmas.py"
VERBATIM)
list(APPEND SRC_MACHO_ALIASES "${_OUTPUT}")
list(APPEND _MACHO_GENERATED_SOURCES "${_OUTPUT}")
list(REMOVE_ITEM SRC_GAME "${_INPUT}")
list(REMOVE_ITEM SRC_GU "${_INPUT}")
endforeach()
list(APPEND SRC_MACHO_ALIASES
"${CMAKE_SOURCE_DIR}/port/src/macho_weak_aliases.s")
set_source_files_properties(${_MACHO_GENERATED_SOURCES}
PROPERTIES GENERATED TRUE)
endif()
# VI mode table (DATA, not a driver): fr.c references osViModeTable ~15x.
# This is the only libultra/io file we compile — the rest are hardware
# drivers that get shimmed in port/src/libultra.c.
@@ -569,6 +673,7 @@ set(SRC
${SRC_LIBULTRARE_LIBC}
${SRC_ASSETS}
${SRC_GU}
${SRC_MACHO_ALIASES}
${SRC_ENGINE}
)
+5 -5
View File
@@ -128,8 +128,8 @@ is right the large majority of the time now, at most a small drift when off; fil
by default (F10 → *All unlocked* opens every level, 007 mode and the full
cheat menu); F10 in-game options overlay (video, input, gameplay, HUD,
graphics, audio; frame cap, MSAA, filtering, FOV, sensitivity, key rebinding,
crosshair, vibration); Windows and
Linux, including Steam Deck.
crosshair, vibration); Windows, Linux and macOS (Intel and Apple Silicon),
including Steam Deck.
**Known issues:**
@@ -152,8 +152,8 @@ Linux, including Steam Deck.
original progression you need to preserve.
- Assorted further cosmetic defects are tracked in
[`docs/dev/GRAPHICS-BACKLOG.md`](docs/dev/GRAPHICS-BACKLOG.md).
- No macOS or ARM support. Keyboard/mouse rebinding shipped in v0.4.0;
controller-button rebinding is not supported yet.
- Keyboard/mouse rebinding shipped in v0.4.0; controller-button rebinding is
not supported yet. No Windows-on-ARM support.
Root causes and fix status for every item: the [release notes](https://github.com/jkdansereau/goldeneye-pc-port/releases)
and the finding log in [`docs/dev/findings.md`](docs/dev/findings.md).
@@ -198,7 +198,7 @@ directionally, on the way to v1.0:
[`docs/dev/findings.md`](docs/dev/findings.md).
- **PAL and JP ROM support** ([issue #85](https://github.com/jkdansereau/goldeneye-pc-port/issues/85)); NTSC-U is the only supported region today.
- **Controller (pad) button rebinding UI** (keyboard/mouse rebinding shipped
in v0.4.0), and macOS/ARM builds.
in v0.4.0).
- **LAN multiplayer**: reviving GoldenEye's original split-screen/deathmatch
netplay across multiple PCs on a local network. Genuinely under
consideration, but early and not started; no ETA.
+15 -7
View File
@@ -1,6 +1,6 @@
---
title: Building
description: Full build and asset-extraction guide for the GoldenEye 007 PC port, covering Windows (MSYS2) and Linux.
description: Full build and asset-extraction guide for the GoldenEye 007 PC port on Windows, Linux, and macOS.
---
## Building the PC port
@@ -27,21 +27,29 @@ for accepted versions and hashes.
### Port build
> **The Windows (MSYS2 MINGW64) path is the primary one.** The Linux build is
> compiled by CI on every push and ships in the release bundle (also
> playtested on Steam Deck hardware); the macOS column is best-effort
> guidance and has never been built or run there. Expect to fix build breaks
> yourself on untested platforms.
> **The Windows (MSYS2 MINGW64) path is the primary one.** Linux is compiled
> by CI and ships in the release bundle. Native Intel macOS builds are also
> supported; Apple Silicon remains untested.
| Need | Windows (MSYS2 MINGW64) | Debian/Ubuntu | macOS (Homebrew) |
|------|------------------------|---------------|------------------|
| toolchain | `mingw-w64-x86_64-toolchain` | `build-essential` | Xcode CLT / `gcc` |
| toolchain | `mingw-w64-x86_64-toolchain` | `build-essential` | Xcode CLT + Homebrew `gcc` |
| CMake | `mingw-w64-x86_64-cmake` | `cmake` | `cmake` |
| SDL2 | `mingw-w64-x86_64-SDL2` | `libsdl2-dev` | `sdl2` |
| zlib | `mingw-w64-x86_64-zlib` | `zlib1g-dev` | `zlib` |
| OpenGL | (in the toolchain) | `libgl1-mesa-dev` | (system) |
| Python 3 | `mingw-w64-x86_64-python` | `python3` | `python3` |
On macOS, install the build dependencies with:
```sh
brew install cmake gcc sdl2 zlib python3
```
The project requires real GNU GCC for the decomp's Plan 9 struct extensions.
Apple's `/usr/bin/gcc` is Clang and is not compatible. CMake automatically
selects Homebrew's versioned `gcc-N`/`g++-N` executables.
### Asset extraction (decompilation toolchain)
The extraction scripts need `binutils-mips-linux-gnu` (or an equivalent MIPS
+24
View File
@@ -580,6 +580,30 @@ through a converter or a runtime bswap fixup reads scrambled.
## C2. Port-layer / SDL shims
- **Darwin assembly uses Mach-O symbol spelling.** GAS absolute symbols that
are `.global foo` / `.set foo, address` on ELF/PE must become `.globl _foo`
/ `.set _foo, address`; Darwin also rejects the ELF `.section .data`
spelling used by these symbol-only files. Generate transformed build-tree
copies rather than changing the cross-platform source files (D294).
- **Darwin GCC cannot lower ELF-style `#pragma weak alias = target`.** It can
ICE in `assemble_alias`; compile generated copies with those pragmas removed
and provide Mach-O indirect symbols (`.set _alias, _target`) separately
(D294).
- **Mach-O's default `__PAGEZERO` reserves the entire low 4 GiB.** A build
can compile and link successfully yet fail every fixed N64 mapping at
runtime (`0x10000000`, `0x70000000`, `0x80000000`). Link with
`-Wl,-pagezero_size,0x10000` so null-page pointers remain protected while
the cartridge and DRAM ranges are available (D294).
- **Darwin has no `MAP_FIXED_NOREPLACE`; a fixed-address hint can relocate.**
Once `__PAGEZERO` is deliberately bounded below the cart range, use
`MAP_FIXED` for the `0x10000000` cartridge mapping. Retaining the advisory
hint silently falls back to a heap ROM and later crashes on direct absolute
ROM-symbol reads (D294).
- **AppKit event polling is main-thread-only.** This port has both a host-main
`videoPumpEvents()` loop and fast3d's render-thread event pump. The latter
must be disabled on macOS or `SDL_PollEvent` raises
`NSInternalInconsistencyException`; the main-thread loop already handles
the complete event set (D294).
- `#include <PR/os.h>` in a port `.c`/`.h` that also sees `<errno.h>`
breaks: `OSContStatus`/`OSContPad` have a `u8 errno;` field vs errno.h's
macro. libultra.c wraps the include in `#pragma push_macro("errno")` /
+7
View File
@@ -311,6 +311,12 @@ static void gfx_sdl_get_dimensions(uint32_t* width, uint32_t* height, int32_t* p
}
static void gfx_sdl_handle_events(void) {
#if defined(__APPLE__)
/* AppKit requires event polling on the process main thread. The host
* loop in videoPumpEvents owns the complete SDL queue, so the scheduler
* render thread must not call SDL_PollEvent on macOS. */
return;
#else
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
@@ -361,6 +367,7 @@ static void gfx_sdl_handle_events(void) {
break;
}
}
#endif
}
/* The window/context are created on the host main thread, but the game's
+11
View File
@@ -28,9 +28,20 @@
* "using typedef-name after 'struct'"), and no C++ TU has an implicit
* declaration needing a fix here. C++ TUs keep their pre-D38 header exposure.
*/
#ifndef _PC_PROTOS_H_
#define _PC_PROTOS_H_
#if defined(__APPLE__)
/* Darwin SDK headers expose these libc calls as fortify function-like
* macros. This legacy declaration list needs their actual symbol names. */
#undef memcpy
#undef snprintf
#undef strcat
#undef strcpy
#undef strncpy
#endif
#if defined(PORT) && defined(__x86_64__) && !defined(__cplusplus)
#include <PR/ultratypes.h> /* u8..s32, f32, size_t (host on PC) */
+12
View File
@@ -28,7 +28,19 @@
#define _PORT_SHIM_OS_H_
#if defined(PORT)
# if defined(__APPLE__)
/* Darwin exposes errno and sprintf as function-like macros. Suppress them
* while parsing the N64 API's errno fields and sprintf declaration. */
# pragma push_macro("errno")
# pragma push_macro("sprintf")
# undef errno
# undef sprintf
# endif
# include "include/PR/os.h"
# if defined(__APPLE__)
# pragma pop_macro("sprintf")
# pragma pop_macro("errno")
# endif
# undef OS_K0_TO_PHYSICAL
# define OS_K0_TO_PHYSICAL(x) ((u32)((char *)(x) - 0x70000000))
+15 -7
View File
@@ -11,6 +11,12 @@
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#if defined(__APPLE__) && !defined(_XOPEN_SOURCE)
#define _XOPEN_SOURCE 700
#endif
#if defined(__APPLE__) && !defined(_DARWIN_C_SOURCE)
#define _DARWIN_C_SOURCE 1
#endif
#include <stdlib.h>
#include <stdio.h>
@@ -303,7 +309,7 @@ static LONG __stdcall crashHandler(PEXCEPTION_POINTERS exinfo)
return EXCEPTION_CONTINUE_EXECUTION;
}
#elif defined(PLATFORM_LINUX)
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS)
#include <ucontext.h>
#include <signal.h>
@@ -341,7 +347,7 @@ static void crashStackTrace(char *msg, int sig, void *pc, ucontext_t *ucontext,
if (siginfo && (sig == SIGSEGV || sig == SIGBUS)) {
CRASH_MSG("FAULT ADDR: %p\n", (void *)siginfo->si_addr);
}
#if defined(PLATFORM_X86_64)
#if defined(PLATFORM_LINUX) && defined(PLATFORM_X86_64)
if (ucontext) {
CRASH_MSG("REGS: Rax=%p Rcx=%p Rdx=%p Rsi=%p Rdi=%p R8=%p R9=%p R10=%p R11=%p\n",
(void *)ucontext->uc_mcontext.gregs[REG_RAX],
@@ -410,10 +416,12 @@ static void crashHandler(int sig, siginfo_t *siginfo, void *ctx)
ucontext_t *ucontext = ctx ? (ucontext_t *)ctx : NULL;
void *pc = NULL;
if (ucontext) {
#ifdef PLATFORM_X86
#if defined(PLATFORM_LINUX) && defined(PLATFORM_X86)
pc = (void *)ucontext->uc_mcontext.gregs[REG_EIP];
#elif defined(PLATFORM_X86_64)
#elif defined(PLATFORM_LINUX) && defined(PLATFORM_X86_64)
pc = (void *)ucontext->uc_mcontext.gregs[REG_RIP];
#elif defined(PLATFORM_MACOS) && defined(PLATFORM_X86_64)
pc = (void *)ucontext->uc_mcontext->__ss.__rip;
#endif
}
@@ -470,7 +478,7 @@ void crashDumpThreads(const unsigned long *tids, const char **names, int count)
}
}
#endif /* PLATFORM_WINDOWS / PLATFORM_LINUX */
#endif /* PLATFORM_WINDOWS / POSIX */
int g_CrashEnabled = 0;
@@ -480,7 +488,7 @@ void crashInit(void)
SetErrorMode(SEM_FAILCRITICALERRORS);
prevExFilter = SetUnhandledExceptionFilter(crashHandler);
g_CrashEnabled = 1;
#elif defined(PLATFORM_LINUX)
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS)
struct sigaction sigact = { 0 };
sigact.sa_flags = SA_SIGINFO | SA_ONSTACK;
sigact.sa_sigaction = crashHandler;
@@ -501,7 +509,7 @@ void crashShutdown(void)
if (prevExFilter) {
SetUnhandledExceptionFilter(prevExFilter);
}
#elif defined(PLATFORM_LINUX)
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_MACOS)
sigaction(SIGSEGV, &prevSigAction, NULL);
sigaction(SIGABRT, &prevSigAction, NULL);
sigaction(SIGBUS, &prevSigAction, NULL);
+15 -2
View File
@@ -53,7 +53,10 @@
#include <windows.h>
#else
#define _GNU_SOURCE /* memfd_create — must precede all system headers */
#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#endif
@@ -101,10 +104,20 @@ void *dramReserve(void)
CloseHandle(hSec);
return v1;
#else
/* memfd + two MAP_SHARED mmaps = one backing store, two views. */
/* One shared file descriptor + two MAP_SHARED mmaps = one backing store,
* two views. Linux can keep it fully anonymous with memfd; Darwin uses a
* POSIX shared-memory object and unlinks its name immediately. */
#if defined(PLATFORM_MACOS)
char shmName[64];
snprintf(shmName, sizeof(shmName), "/ge007_dram_%ld", (long)getpid());
int fd = shm_open(shmName, O_RDWR | O_CREAT, 0600);
if (fd >= 0)
shm_unlink(shmName);
#else
int fd = memfd_create("ge007_dram", 0);
#endif
if (fd < 0) {
sysFatalError("dram: memfd_create failed");
sysFatalError("dram: could not create shared backing store");
}
if (ftruncate(fd, DRAM_SIZE) != 0) {
sysFatalError("dram: ftruncate failed");
+1 -1
View File
@@ -977,7 +977,7 @@ static void piServiceDma(s32 direction, u32 srcPA, void *dstVA, u32 size)
char win[1200] = "";
char *wp = win;
for (int i = 0; i < 32; i++) {
wp += snprintf(wp, win + sizeof(win) - (wp - win),
wp += snprintf(wp, sizeof(win) - (size_t)(wp - win),
" %p", (void *)sp[i]);
}
#if defined(PLATFORM_WINDOWS)
+25
View File
@@ -0,0 +1,25 @@
/* Mach-O equivalents of the decomp's `#pragma weak alias = target`. */
.globl _g_DebugPortalsInputBufferSource1
.set _g_DebugPortalsInputBufferSource1, _g_DebugPortalsInputBuffer1
.globl _g_DebugPortalsInputBufferSource2
.set _g_DebugPortalsInputBufferSource2, _g_DebugPortalsInputBuffer2
.globl _g_DebugPortalsInputBufferSource3
.set _g_DebugPortalsInputBufferSource3, _g_DebugPortalsInputBuffer3
.globl _g_DebugPortalsInputBufferSource4
.set _g_DebugPortalsInputBufferSource4, _g_DebugPortalsInputBuffer4
.globl _objectiveGetStatus_WEAK
.set _objectiveGetStatus_WEAK, _get_status_of_objective
.globl _spec_keyboard_row_caps_z_x_c_v
.set _spec_keyboard_row_caps_z_x_c_v, _spec_keyboard_buffer
.globl _fsin
.set _fsin, ___sinf
.globl _sinf
.set _sinf, ___sinf
.globl _fcos
.set _fcos, ___cosf
.globl _cosf
.set _cosf, ___cosf
+9 -2
View File
@@ -36,6 +36,7 @@ extern int snprintf(char *str, size_t maxsize, const char *format, ...);
/* POSIX: mmap the ROM at the fixed cart address (mirrors the VirtualAlloc
* path). <sys/mman.h> is a host header the decomp include path does not
* shadow. */
#include <errno.h>
#include <sys/mman.h>
#endif
@@ -382,9 +383,15 @@ int romdataInit(void)
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
#ifdef MAP_FIXED_NOREPLACE
flags |= MAP_FIXED_NOREPLACE;
#elif defined(PLATFORM_MACOS)
/* __PAGEZERO ends at CART_BASE in the macOS build, so this range
* is deliberately vacant. Darwin has no MAP_FIXED_NOREPLACE and
* otherwise treats CART_BASE only as a hint, relocating it. */
flags |= MAP_FIXED;
#endif
void *at = mmap((void *)(uintptr_t)CART_BASE, maplen,
PROT_READ | PROT_WRITE, flags, -1, 0);
int mapErrno = errno;
if (at != MAP_FAILED && at == (void *)(uintptr_t)CART_BASE) {
mappedLen = maplen;
return romdataFinishCartMap(tok, img, sideTotal, cgTotal);
@@ -392,8 +399,8 @@ int romdataInit(void)
if (at != MAP_FAILED)
munmap(at, maplen);
sysLogPrintf(LOG_WARNING, "romdataInit: could not map 0x%08X "
"(ASLR/kernel refused the fixed address); using heap "
"copy — direct ROM reads will fail", CART_BASE);
"(mmap result=%p errno=%d); using heap copy — direct "
"ROM reads will fail", CART_BASE, at, mapErrno);
#endif
}
+6 -2
View File
@@ -13,6 +13,9 @@
#include <string.h>
#include <math.h>
/* Prevent GCC's implicit declaration warning */
extern void exit(int status);
#if defined(_WIN32)
#include <direct.h>
#define GE_MKDIR(p) _mkdir(p)
@@ -794,8 +797,9 @@ void videoStartFrame(void)
* CREATED the window pumps them — and every game thread can be blocked on a
* message queue at any time. So the host main thread (which created the
* window in videoInit) must keep pumping; otherwise the window goes
* "Not Responding" and ESC/close never arrive. fast3d's own handle_events
* (which runs during rendering) remains as a backstop.
* "Not Responding" and ESC/close never arrive. On macOS AppKit strictly
* requires this main-thread pump, so fast3d's render-thread event handler is
* disabled there; on other platforms it remains as a backstop.
*/
void videoPumpEvents(void)
{
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""Convert ELF/PE GAS absolute symbols to Mach-O spelling."""
import pathlib
import re
import sys
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} INPUT OUTPUT", file=sys.stderr)
return 2
source = pathlib.Path(sys.argv[1])
output = pathlib.Path(sys.argv[2])
lines = []
for line in source.read_text(encoding="utf-8").splitlines():
if re.match(r"^\s*\.section\s+\.data\s*$", line):
continue
match = re.match(r"^(\s*)\.global\s+([A-Za-z_]\w*)\s*$", line)
if match:
lines.append(f"{match.group(1)}.globl _{match.group(2)}")
continue
match = re.match(
r"^(\s*)\.set\s+([A-Za-z_]\w*)(\s*,.*)$", line
)
if match:
lines.append(
f"{match.group(1)}.set _{match.group(2)}{match.group(3)}"
)
continue
lines.append(line)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text("\n".join(lines) + "\n", encoding="utf-8")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
"""Remove ELF-style weak aliases from a C source copied for Mach-O."""
import pathlib
import re
import sys
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} INPUT OUTPUT", file=sys.stderr)
return 2
source = pathlib.Path(sys.argv[1])
output = pathlib.Path(sys.argv[2])
text = source.read_text(encoding="utf-8")
text = re.sub(r"^[ \t]*#pragma[ \t]+weak[^\n]*\n", "", text,
flags=re.MULTILINE)
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(text, encoding="utf-8")
return 0
if __name__ == "__main__":
raise SystemExit(main())