macho_block_alt_entry.sh (3008B)
1 #!/usr/bin/env bash 2 # Mach-O MH_SUBSECTIONS_VIA_SYMBOLS regression: relocation-anchor symbols for 3 # switch/label blocks must be N_ALT_ENTRY symbols pinned inside their function, 4 # not independently collectible atoms. Otherwise --gc-sections can retain the 5 # function's entry atom while dropping a directly-branched-to switch dispatch 6 # or common return block (intra-function branches are already resolved and do 7 # not carry linker relocations). 8 set -euo pipefail 9 10 ROOT="$(cd "$(dirname "$0")/../.." && pwd)" 11 KIT="${KIT:-$ROOT/build/kit}" 12 ROUNDTRIP="${ROUNDTRIP:-$ROOT/build/test/kit-roundtrip-macho}" 13 WORK="$ROOT/build/test/opt/macho_block_alt_entry" 14 mkdir -p "$WORK" 15 16 cat > "$WORK/dispatch.c" <<'EOF' 17 int dispatch(unsigned x) { 18 if (x < 256) return 7; 19 switch (x) { 20 case 256: return 11; 21 case 257: return 13; 22 case 258: return 17; 23 case 259: return 19; 24 case 260: return 23; 25 case 261: return 29; 26 case 262: return 31; 27 case 263: return 37; 28 case 264: return 41; 29 default: return 43; 30 } 31 } 32 EOF 33 34 cat > "$WORK/main.c" <<'EOF' 35 extern int dispatch(unsigned); 36 int main(void) { return dispatch(123) == 7 ? 0 : 1; } 37 EOF 38 39 COMMON=(-target aarch64-apple-darwin -O1 -ffunction-sections 40 -fdata-sections -ffreestanding) 41 "$KIT" cc "${COMMON[@]}" -c "$WORK/dispatch.c" -o "$WORK/dispatch.o" \ 42 > "$WORK/dispatch.cc.out" 2>&1 43 "$KIT" cc "${COMMON[@]}" -c "$WORK/main.c" -o "$WORK/main.o" \ 44 > "$WORK/main.cc.out" 2>&1 45 46 # Read and re-emit the defining object before linking. This makes the test 47 # cover both halves of the format boundary: Mach-O read must collapse pinned 48 # block symbols into their owner atom, and emit must preserve the subordinate 49 # semantic as N_ALT_ENTRY on the second object too. 50 "$ROUNDTRIP" --require-atom-subordinate "$WORK/dispatch.o" \ 51 "$WORK/dispatch.roundtrip.o" > "$WORK/dispatch.roundtrip.out" 2>&1 52 53 # Force the serialized Mach-O reader/linker path: compiling and linking in one 54 # driver invocation can keep the original ObjBuilder and would not exercise 55 # MH_SUBSECTIONS_VIA_SYMBOLS reconstruction. 56 "$KIT" cc -target aarch64-apple-darwin -nostdlib -Wl,--gc-sections \ 57 -Wl,-e,main "$WORK/main.o" "$WORK/dispatch.roundtrip.o" -o "$WORK/linked" \ 58 > "$WORK/link.out" 2>&1 59 "$KIT" objdump -d "$WORK/linked" > "$WORK/linked.dis" 2>&1 60 61 # The case body and indirect table dispatch live after block-label boundaries. 62 # Without N_ALT_ENTRY they are collected and the surviving fast-path branches 63 # outside __text; retaining both instructions pins the full function content. 64 if ! grep -Eq '\bmovz[[:space:]]+w0, 0xb\b' "$WORK/linked.dis"; then 65 printf 'macho_block_alt_entry FAILED: case block was GC-collected\n' >&2 66 sed 's/^/ | /' "$WORK/linked.dis" >&2 67 exit 1 68 fi 69 if ! grep -Eq '\bbr[[:space:]]+x[0-9]+\b' "$WORK/linked.dis"; then 70 printf 'macho_block_alt_entry FAILED: switch dispatch was GC-collected\n' >&2 71 sed 's/^/ | /' "$WORK/linked.dis" >&2 72 exit 1 73 fi 74 75 printf 'macho_block_alt_entry: OK (block anchors stay pinned through Mach-O GC)\n'