Skip to content

Commit 8164a0b

Browse files
committed
fix linker error due to personality localization
1 parent 8b5d5e1 commit 8164a0b

4 files changed

Lines changed: 43 additions & 29 deletions

File tree

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
#!/usr/bin/env bash
2-
# Localize all non-exported symbols in an Apple static library so that its
3-
# bundled mimalloc does not coalesce with Unity 6.5's built-in mimalloc when the
4-
# library is statically linked into UnityFramework (iOS `__Internal`).
2+
# Localize the bundled mimalloc symbols in an Apple static library so they do
3+
# not coalesce with Unity 6.5's built-in mimalloc when the library is statically
4+
# linked into UnityFramework (iOS `__Internal`).
5+
#
6+
# Only mimalloc's own symbols are localized. Rust runtime symbols (including
7+
# personality routines) are intentionally left global: localizing them would
8+
# give every linked static lib its own personality routine, and compact-unwind
9+
# can encode at most 3 per image ("ld: Too many personality routines ...").
510
#
611
# Requires the library to have been compiled with `-fno-common` (see the CI
712
# workflow) so that mimalloc's tentative definitions (e.g. `_mi_page_map`) are
@@ -15,9 +20,9 @@ LIB="$1" # path to the .a (e.g. libunienc_c.a)
1520
ARCH="$2" # ld arch name (e.g. arm64)
1621
SDK="${3:-iphoneos}" # xcrun SDK (e.g. iphoneos)
1722
PLATFORM="${4:-ios}" # -platform_version platform name (e.g. ios)
18-
MIN_OS="${5:-13.0}" # -platform_version minimum OS version
23+
MIN_OS="${5:-10.0}" # -platform_version minimum OS version
1924
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20-
EXPORTS="$SCRIPT_DIR/../../InstantReplay.Externals/unienc/crates/unienc_c/apple-exports.txt"
25+
UNEXPORTS="$SCRIPT_DIR/../../InstantReplay.Externals/unienc/crates/unienc_c/apple-mimalloc-unexports.txt"
2126

2227
if [ ! -f "$LIB" ]; then
2328
echo "ERROR: static library not found: $LIB" >&2
@@ -32,7 +37,7 @@ trap 'rm -rf "$WORK"' EXIT
3237
# Extract every archive member as a loose object. We deliberately do NOT use
3338
# `ld -r -force_load <archive>`: the modern linker (ld-prime) localizes *all*
3439
# symbols of a force-loaded archive, which would strip the `_unienc*` exports
35-
# too. Passing loose objects makes `-exported_symbols_list` behave as intended.
40+
# and the Rust runtime symbols too. Loose objects make the symbol lists behave.
3641
( cd "$WORK" && ar x "$LIB_ABS" )
3742
member_count="$(ar t "$LIB_ABS" | grep -Ec '\.o$' || true)"
3843
extracted_count="$(find "$WORK" -maxdepth 1 -name '*.o' | wc -l | tr -d ' ')"
@@ -42,35 +47,36 @@ if [ "$member_count" != "$extracted_count" ]; then
4247
fi
4348

4449
# Partial link into a single object.
45-
# -exported_symbols_list : demote every global NOT matching `_unienc*` to a
46-
# private-extern symbol.
50+
# -unexported_symbols_list : demote ONLY the listed mimalloc symbols to
51+
# private-extern (leaves everything else global).
4752
# -r (without -keep_private_externs) : convert those private-externs (and the
48-
# ones already produced by `-fvisibility=hidden`) into
49-
# true local symbols.
53+
# ones already produced by `-fvisibility=hidden`)
54+
# into true local symbols.
5055
# -platform_version : required by ld-prime even for a `-r` link.
5156
( cd "$WORK" && xcrun --sdk "$SDK" ld -r -arch "$ARCH" \
5257
-platform_version "$PLATFORM" "$MIN_OS" "$SDK_VER" \
53-
-exported_symbols_list "$EXPORTS" \
58+
-unexported_symbols_list "$UNEXPORTS" \
5459
*.o -o merged.o )
5560

5661
rm -f "$LIB_ABS"
5762
xcrun libtool -static -o "$LIB_ABS" "$WORK/merged.o"
5863

5964
# --- Verify (CI gate; also guards against future linker behaviour changes) ---
60-
echo "=== exported (global) symbols after localization ==="
61-
nm -gU "$LIB_ABS" | sort -u
62-
6365
# (a) No mimalloc symbol may remain external or private-external. `nm -gU` lists
6466
# both (private-externs still coalesce), so it must contain zero of them.
65-
if nm -gU "$LIB_ABS" | grep -iE '_mi_|_heap_main|_theap_main|mi_unity_'; then
67+
# The `_mi_` substring also matches `__mi_*` / `___mi_*`.
68+
if xcrun nm -gU "$LIB_ABS" | grep -iE '_mi_|_heap_main|_theap'; then
6669
echo "FAIL: mimalloc symbols are still (private-)external -> would coalesce with Unity" >&2
70+
echo " (if _mi_page_map is listed, the build is missing -fno-common)" >&2
6771
exit 1
6872
fi
6973

70-
# (b) FFI entry points must remain global.
71-
if ! nm -gU "$LIB_ABS" | grep -q '_unienc_UnityPluginLoad'; then
74+
# (b) FFI entry points must remain global. Use `grep -c` (not `grep -q`): under
75+
# `set -o pipefail`, `grep -q` exits on first match and SIGPIPEs `nm`, whose
76+
# non-zero status would then be reported as a (spurious) failure.
77+
if [ "$(xcrun nm -gU "$LIB_ABS" | grep -c '_unienc_UnityPluginLoad')" -eq 0 ]; then
7278
echo "FAIL: _unienc_UnityPluginLoad is no longer exported" >&2
7379
exit 1
7480
fi
7581

76-
echo "Localization OK: $(nm -gU "$LIB_ABS" | grep -c '_unienc') unienc symbols exported, 0 mimalloc symbols external"
82+
echo "Localization OK: $(xcrun nm -gU "$LIB_ABS" | grep -c '_unienc') unienc symbols exported, 0 mimalloc symbols external"

.github/workflows/build-unienc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ jobs:
135135
# mimalloc. Injected via cc-rs's target CFLAGS so no submodule change
136136
# is needed. Only aarch64 is built for iOS (see matrix).
137137
CFLAGS_aarch64-apple-ios: -fno-common
138+
IPHONEOS_DEPLOYMENT_TARGET: 10.0
138139
# Localize the bundled mimalloc so it does not coalesce with Unity 6.5's
139140
# built-in mimalloc when statically linked into UnityFramework.
140141
- name: Localize non-exported symbols (Unity variant only)

InstantReplay.Externals/unienc/crates/unienc_c/apple-exports.txt

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# mimalloc symbols to localize when libunienc_c.a is statically linked into
2+
# UnityFramework (iOS). Consumed via `ld -r -unexported_symbols_list`.
3+
#
4+
# We localize ONLY mimalloc's own symbols so they no longer coalesce with Unity
5+
# 6.5's built-in mimalloc. Everything else (the `_unienc*` FFI entry points AND
6+
# the Rust runtime symbols such as `rust_eh_personality`) is left global on
7+
# purpose: localizing personality routines would give each linked static lib its
8+
# own copy, and the compact-unwind format can encode at most 3 personality
9+
# routines per image -> "ld: Too many personality routines for compact unwind".
10+
#
11+
# The three underscore depths cover the C sources `mi_*`, `_mi_*` and `__mi_*`
12+
# (Mach-O prepends one leading underscore). Verified to match all 432 mimalloc
13+
# symbols in the current unity-fork build with zero false positives.
14+
_mi_*
15+
__mi_*
16+
___mi_*
17+
_heap_main
18+
_theap_main

0 commit comments

Comments
 (0)