Skip to content

Do not set an ELF cold-section name on Mach-O targets - #26

Open
dougchansan wants to merge 1 commit into
ExpansionPak:mainfrom
dougchansan:fix/macho-cold-section
Open

Do not set an ELF cold-section name on Mach-O targets#26
dougchansan wants to merge 1 commit into
ExpansionPak:mainfrom
dougchansan:fix/macho-cold-section

Conversation

@dougchansan

Copy link
Copy Markdown
Contributor

Summary

Fixes #25 — the LLVM backend cannot emit a module on macOS.

markColdFixup() in src/backend/llvm/fp_fixups.cpp names the FP fixup helpers ".text.unlikely.<fn>" unconditionally. Mach-O section specifiers must be "__SEGMENT,__section", and its writer rejects anything else outright, so on Darwin targets emission aborts:

LLVM ERROR: Global variable 'fix_pair_nan_f64' has an invalid section specifier
'.text.unlikely.fix_pair_nan_f64': mach-o section specifier requires a segment and
section separated by a comma.

Building Luigi's Mansion (GLME01) for aarch64-apple-darwin died at chunk 57 of 4164.

The change

Skip only the section name, and only on Mach-O. ELF and COFF both accept it and keep it, so x86-64 Windows and Linux codegen are byte-for-byte unchanged. Attribute::Cold and Attribute::NoInline still apply everywhere, so the placement hint itself is not lost — only the ELF-shaped name that Mach-O cannot parse.

Verification

  • macOS (Apple Silicon M5, clang/LLVM 20): with the name suppressed, all 4164 chunks emit and the module runs correctly — Luigi's Mansion foyer.sav, uncapped, interleaved blocks with a discarded warm run per arm: LLVM median 81.2 fps vs 79.1 for the C backend on the same host, no freeze, end frames advancing normally every run.
  • Windows x86-64 (MSVC, LLVM 20): builds clean; the guard is false for COFF so behaviour is unchanged.

One related observation while setting the macOS side up, not addressed here: at this commit the C backend emits calls to ppc_fp_available_inline, which does not exist in the ModernGekko GXRuntime we build against (GXRuntime/include/core/cpu.h declares only ppc_fp_available), so a same-commit C module could not be built on that checkout for comparison.

markColdFixup() names the FP fixup helpers ".text.unlikely.<fn>"
unconditionally. Mach-O section specifiers are "__SEGMENT,__section" and
its writer rejects anything else outright, so on Darwin targets module
emission aborts:

  LLVM ERROR: Global variable 'fix_pair_nan_f64' has an invalid section
  specifier '.text.unlikely.fix_pair_nan_f64': mach-o section specifier
  requires a segment and section separated by a comma.

Building Luigi's Mansion for aarch64-apple-darwin died at chunk 57 of
4164; with the name suppressed on Mach-O all 4164 chunks emit and the
module runs clean (foyer.sav, median 81.2 fps against 79.1 for the C
backend on the same host).

ELF and COFF both accept the name, so they keep it. The Cold and
NoInline attributes carry the placement hint on every target regardless,
which is why dropping only the name costs nothing.
@dougchansan

Copy link
Copy Markdown
Contributor Author

Verified on Apple Silicon from a completely clean tree — no local workaround anywhere.

Provenance first, because the previous session on that machine had a hand-applied hack and it mattered to rule it out: that hack was never in a git checkout. It lived in ~/dolrecomp-llvm-src, a tarball export that is not a repo. The reference checkout was already clean. Verification used a fresh shallow clone of this branch at 585ddc8, git status clean, configured with the same flags as the reference build (Release, Ninja, DOLRECOMP_ENABLE_LLVM=ON, LLVM_DIR=/opt/homebrew/opt/llvm@20, llvm@20 clang/clang++).

Generation now completes on two titles, 9,967 chunks, zero errors:

title chunks result
Luigi's Mansion (GLME01) 4164 / 4164 rc=0, 143,142,328-byte dylib
Mario Kart Double Dash (GM4E01) 5803 / 5803 rc=0, 263,626,648-byte dylib

No occurrences of invalid section specifier or LLVM ERROR in either log. The Luigi's Mansion module loads (entry=0x80003100), boots, and advances frames normally (3643 → 4679 across a 30 s window).

Performance from the clean build matches the patched build, so the fix costs nothing: Luigi's Mansion foyer.sav, uncapped, LLVM 80.44 fps vs C 78.47 fps — ratio 1.025x, against 1.026x measured previously with the hack applied.

Two caveats worth recording rather than hiding:

  • That C control is from an older dolrecomp revision (native-llvm-v4, cpu_abi=4), not a same-commit rebuild, so the ratio compares this branch's LLVM against a historical C build. A same-commit C module could not be built there: --backend c emits calls to ppc_psq_load_inline, which exists in DolRecomp's src/cpu/cpu.h but not in the vendored GXRuntime headers the module template compiles against. That is DolRecomp/ModernGekko version skew, unrelated to this PR.
  • The host is shared and was heavily loaded (27 logged-in users; load average climbed from ~2 to 35–60 within minutes). Every run measured under load was discarded; the numbers above come from a quiet window at load 2.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LLVM backend fails to emit on macOS: ELF section name rejected by Mach-O writer

1 participant