Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
266 commits
Select commit Hold shift + click to select a range
761d58b
fix(macho): correct PAGEOFF12 scaling for 128-bit SIMD loads
gilescope Apr 9, 2026
51a01d5
fix(macho): increase LINKEDIT size estimate for large binaries
gilescope Apr 9, 2026
7ee1572
fix(macho): increase LINKEDIT buffer estimate for large Rust binaries
gilescope Apr 9, 2026
8ade4ab
feat: add lld MachO test suite (Apache 2.0 + LLVM Exception)
gilescope Apr 9, 2026
932de9a
feat: add sold Mach-O test suite (MIT)
gilescope Apr 9, 2026
907bd7a
chore: fmt
gilescope Apr 9, 2026
2ee5b04
fix(macho): fix dylib n_sect and entry point validation
gilescope Apr 9, 2026
a6e4042
feat(macho): add -filelist support and accept more ld64 flags
gilescope Apr 9, 2026
64f0009
feat(macho): implement -force_load flag
gilescope Apr 9, 2026
c931ea7
fix(macho): implement whole-archive section and symbol loading
gilescope Apr 9, 2026
bcd8109
feat(macho): add -help flag and un-ignore response-file test
gilescope Apr 9, 2026
8e03a50
fix(macho): implement common symbol support
gilescope Apr 9, 2026
888a3e5
fix(macho): correct TLS block offset for TBSS symbols
gilescope Apr 9, 2026
b64b838
fix(macho): correct N_EXT in symtab and implement -x flag
gilescope Apr 9, 2026
7e1cd3a
feat(macho): emit LC_UUID for executables
gilescope Apr 9, 2026
a9db2e6
fix(macho): improve LINKEDIT structure for strip compatibility
gilescope Apr 9, 2026
95b13dc
feat: implement additional args
gilescope Apr 10, 2026
bd99707
chore: fmt
gilescope Apr 10, 2026
e374093
feat(macho): implement Mach-O linker flags with shared ELF infrastruc…
gilescope Apr 10, 2026
0b1fae7
feat(macho): implement -F/-framework/-weak_framework/-needed_framework
gilescope Apr 10, 2026
8256503
feat(macho): implement prefix link modifiers and update plan
gilescope Apr 10, 2026
db9a4af
fix(macho): use search_paths_first order for -l library resolution
gilescope Apr 10, 2026
17ace6a
feat(macho): implement exports trie filtering via export/unexport lists
gilescope Apr 10, 2026
a12bf8e
feat(macho): implement -search_dylibs_first flag and unified search loop
gilescope Apr 10, 2026
67cc25d
feat(macho): implement dylib input consumption
gilescope Apr 10, 2026
5e5ed8f
feat(macho): synthesize N_OSO stab entries for debug info
gilescope Apr 10, 2026
120f45f
feat(macho): differentiate weak/reexport dylib load commands
gilescope Apr 10, 2026
469db0c
docs: add cstring merge implementation plan
gilescope Apr 10, 2026
4e52ba0
feat(macho): add merged string write and relocation infrastructure
gilescope Apr 10, 2026
35c5f39
feat(macho): enable S_CSTRING_LITERALS section merging
gilescope Apr 10, 2026
00db43e
feat(macho): handle .tbd positional inputs and deferred framework res…
gilescope Apr 10, 2026
69a7f03
feat(macho): implement $ld$ TBD directives and dylib symbol parsing
gilescope Apr 10, 2026
2e9338f
refactor(macho): clean up undefined symbol check after investigation
gilescope Apr 10, 2026
c483d93
fix(macho): collect weak_symbols from TBD re-export sections
gilescope Apr 10, 2026
c7874c5
feat(macho): recursively trace LC_REEXPORT_DYLIB for symbol resolution
gilescope Apr 10, 2026
6780b02
chore: fmt
gilescope Apr 10, 2026
6c991af
feat(macho): implement -reexport_library, -weak_library, -Z, -U, -pag…
gilescope Apr 10, 2026
4b6d88c
fix(macho): match sold error message format for undefined/duplicate s…
gilescope Apr 10, 2026
1307903
feat(macho): implement -oso_prefix with canonicalized OSO paths
gilescope Apr 10, 2026
68901ba
feat(macho): implement -add_ast_path (N_AST stab entries)
gilescope Apr 10, 2026
733709a
feat(macho): implement -dead_strip_dylibs with -needed tracking
gilescope Apr 10, 2026
5e20a86
feat(macho): implement -v version output
gilescope Apr 10, 2026
655978d
feat(macho): implement -map link map file writer
gilescope Apr 10, 2026
3314aee
fix(macho): align dylib symtab to 8 bytes in LINKEDIT
gilescope Apr 10, 2026
01ce73d
feat(macho): implement MH_DEAD_STRIPPABLE_DYLIB and -mark_dead_stripp…
gilescope Apr 10, 2026
9ba075b
feat(macho): implement -hidden-l (archive symbol export filtering)
gilescope Apr 10, 2026
fe65547
feat(macho): implement -application_extension warning and -w suppression
gilescope Apr 10, 2026
f2313a1
feat(macho): implement -U (dynamic undefined) and -w, -application_ex…
gilescope Apr 10, 2026
edbd885
feat(macho): add DYLD_CHAINED_IMPORT_ADDEND support (partial)
gilescope Apr 10, 2026
3d8ef01
feat(macho): hit 100 passing tests - dependency info, lc-build-version
gilescope Apr 10, 2026
a58f79a
chore: fmt
gilescope Apr 10, 2026
7686197
feat(macho): 100→124 passing tests — LTO, fixup chains, debuginfo, an…
gilescope Apr 10, 2026
656eef3
feat(macho): ObjC _objc_msgSend$ stub redirect, order-file parsing, w…
gilescope Apr 10, 2026
9a04f92
chore: add out/ and ld64 to gitignore, remove test artifacts
gilescope Apr 10, 2026
b6f890d
feat(macho): subsections-via-symbols (reverted - needs caching), ObjC…
gilescope Apr 10, 2026
0301084
fix(macho): skip unaligned rebase check for __llvm metadata sections
gilescope Apr 10, 2026
27fb905
chore: fmt
gilescope Apr 10, 2026
0f89174
docs: add implementation plans for remaining 10 Mach-O tests
gilescope Apr 10, 2026
de2350b
fix: got to wasm build
gilescope Apr 11, 2026
2d1c2ff
chore: fmt
gilescope Apr 11, 2026
3ce83f6
feat(wasm): add initial WASM linking support (Tier 1)
gilescope Apr 11, 2026
d06a368
feat(wasm): Tier 2 - relocations and expanded flag parsing
gilescope Apr 11, 2026
5144cdf
feat(wasm): function-level GC and improved export handling
gilescope Apr 11, 2026
e6345db
feat(wasm): name section, function GC, tightened test patterns
gilescope Apr 11, 2026
92b7f2f
feat(wasm): global section, R_WASM_GLOBAL_INDEX_LEB, memory sizing
gilescope Apr 11, 2026
4acf5aa
feat(wasm): refine test patterns, unlock function-imports test
gilescope Apr 11, 2026
2f7d8ca
feat(wasm): allowlist for known-passing tests, 34 tests passing
gilescope Apr 11, 2026
d3eb3ce
feat(wasm): data section, section_data pipeline, spec validation
gilescope Apr 11, 2026
9e4bf57
feat(wasm): import section per spec §9.2 and §9.6
gilescope Apr 11, 2026
147b5c7
feat(wasm): R_WASM_MEMORY_ADDR_* relocations per spec §9.4
gilescope Apr 11, 2026
3eabb39
feat(wasm): complete relocation coverage per spec §9.4
gilescope Apr 11, 2026
05d990e
feat(wasm): complete Tier 2 — segment info, data relocs, linker globals
gilescope Apr 11, 2026
d60c246
docs(wasm): add wasm-todo.md with known gaps and future work
gilescope Apr 11, 2026
995deaf
feat(wasm): Tier 5 — __wasm_call_ctors synthesis per spec §6
gilescope Apr 11, 2026
496e3aa
feat(wasm): complete Tier 3 — import-table, export-table, growable-table
gilescope Apr 11, 2026
4824baa
feat(wasm): --export-dynamic exports all non-hidden functions
gilescope Apr 11, 2026
c7520dc
feat(wasm): Tier 5 — ctors on-demand, NO_STRIP flag per spec §4.2
gilescope Apr 11, 2026
21e2fa6
feat(wasm): enable llc-based tests, allowlist expansion — 44 tests
gilescope Apr 11, 2026
61202c8
feat(wasm): cross-object data symbol resolution
gilescope Apr 11, 2026
c66840a
feat(wasm): WASM_SYM_EXPORTED flag per spec §4.2
gilescope Apr 11, 2026
bed291b
feat(wasm): weak symbol resolution, call_indirect tests, Phase 6 start
gilescope Apr 11, 2026
6ee2b8a
feat(wasm): memory layout flags — initial-memory, max-memory, global-…
gilescope Apr 11, 2026
0f2b920
feat(wasm): enable LTO error-path tests, KNOWN_PASSING cleanup
gilescope Apr 11, 2026
195fc4f
chore(wasm): fix KNOWN_PASSING for lto/ path, export test passes
gilescope Apr 11, 2026
354a16f
feat(wasm): native split-file support in test runner
gilescope Apr 11, 2026
c0af9fa
feat(wasm): add wilt crate for post-link wasm optimization passes
gilescope Apr 12, 2026
5c4ff8f
fix(macho): restore strip(1) compatibility by un-padding LINKEDIT symtab
gilescope Apr 12, 2026
2237113
fix(macho): allow self-imports under -flat_namespace
gilescope Apr 12, 2026
8f19377
chore: untrack stray test-run artifacts and ignore them
gilescope Apr 12, 2026
255160b
docs(wasm): accurate status in wasm-todo.md
gilescope Apr 12, 2026
9b4ba5f
feat(wasm): warn on unhandled relocation types
gilescope Apr 12, 2026
bbfae0a
feat(wasm): implement GLOBAL_INDEX_I32, TABLE_NUMBER_LEB, FUNCTION_IN…
gilescope Apr 12, 2026
87bf606
feat(wasm): implement 64-bit relocation types (memory64 opcodes)
gilescope Apr 12, 2026
09bde02
feat(wasm): implement PIC-relative and LOCREL relocation types
gilescope Apr 12, 2026
f4ca707
feat(wasm): pass-through support for EH tag section and R_WASM_TAG_IN…
gilescope Apr 12, 2026
53bdad4
feat(wasm): proper EH tag merge mirroring function-merge pipeline
gilescope Apr 12, 2026
f873a17
docs(wasm): list spec features that ship without tests
gilescope Apr 12, 2026
e6bec74
test(wasm): round-trip unit tests for padded LEB writers and tag parse
gilescope Apr 12, 2026
0d1681f
feat(wasm): merge target_features per §8 with conflict detection
gilescope Apr 12, 2026
a1fe142
feat(wasm): §8 shared-memory / atomics conflict check in target_features
gilescope Apr 12, 2026
fa533d7
feat(wasm): introduce Addr type alias behind wasm-addr64 feature
gilescope Apr 12, 2026
e6edac8
feat(wasm): accept --features=+memory64 / -mwasm64 and detect mem64 i…
gilescope Apr 12, 2026
9b32177
feat(wasm): emit memory type with 0x04 flag under --features=+memory64
gilescope Apr 12, 2026
3c7780e
feat(wasm): emit linker-synth globals as i64 under memory64
gilescope Apr 12, 2026
ca1ce70
feat(wasm): active data segment offsets as i64.const under memory64
gilescope Apr 12, 2026
ae23b0b
test(wasm): end-to-end mem64 synthesis smoke test
gilescope Apr 12, 2026
6b35128
fix(wasm): opcode-aware remap_call_targets with bulk-memory coverage
gilescope Apr 12, 2026
6775ac5
fix(wasm): gc_functions BFS walker now shares the opcode-aware walker
gilescope Apr 12, 2026
b72be2b
fix(wilt): compress pass consumes 0xFC sub-opcode immediates
gilescope Apr 12, 2026
32862ec
feat(wasm): recognise -pie / --pie / --experimental-pic as is_pic
gilescope Apr 12, 2026
0ec3460
feat(wasm): element segment init uses global.get __table_base under PIC
gilescope Apr 12, 2026
78eb28a
test(wasm): pin REL_SLEB static behaviour + document PIC gap punchlist
gilescope Apr 12, 2026
db13396
feat(wasm): internalise GOT.func.* / GOT.mem.* imports under static link
gilescope Apr 12, 2026
ee34f19
test(wasm): pin GOT.func import parse path + document PIC punchlist
gilescope Apr 12, 2026
95aacdf
feat(wasm): synthesize __memory_base / __table_base under static link
gilescope Apr 12, 2026
b638261
feat(wasm): apply custom-section relocations with 0xFFFFFFFF sentinel
gilescope Apr 12, 2026
e6b4266
feat(wasm): more custom-section reloc types in the debug passthrough
gilescope Apr 12, 2026
a8fcc8d
docs(wasm): scope pic-static gap after landing custom-section relocs
gilescope Apr 12, 2026
2eec6a4
feat(wasm): static-PIC mode with base-global triad and GOT dedup
gilescope Apr 12, 2026
d5e730b
feat(wasm): pic-static sub-gaps — internal naming, ordering, table-sl…
gilescope Apr 12, 2026
d97c80f
feat(wasm): pic-static passes (import-GOT slots + name subsection 9)
gilescope Apr 12, 2026
74cec21
docs(wasm): scope the four remaining ignored LLD PIC tests
gilescope Apr 12, 2026
5e47fdc
feat(wasm): TLS synthesis, lazy linker globals, @TBREL bias, mem64 PI…
gilescope Apr 12, 2026
ecbd940
fix(wasm): GC indexes into defined-function space, not wasm-binary space
gilescope Apr 12, 2026
38438b0
fix(wasm): GC body walker indexes defined-only, not wasm-binary
gilescope Apr 12, 2026
7efe3cf
refactor(wasm): register symbol aliases and dedupe name section by fu…
gilescope Apr 12, 2026
d98b013
feat(wasm): --export=<sym> fans out to every alias sharing the function
gilescope Apr 12, 2026
a293c21
docs(wasm): bump passing LLD test count to 74/223
gilescope Apr 12, 2026
481e345
fix(wasm): merge producers custom section instead of concatenating
gilescope Apr 12, 2026
f0d9b45
fix(wasm): emit producers after name, before target_features
gilescope Apr 12, 2026
76d9ed7
fix(wasm): patch FUNCTION_OFFSET_I32 and SECTION_OFFSET_I32 debug relocs
gilescope Apr 12, 2026
ba428dd
test(wasm): enable debug-undefined-fs, now passes via debug reloc fix
gilescope Apr 12, 2026
e8986fc
wilt: Plan B + Plan C foundations (Group B passes, IR, LinkerHints)
gilescope Apr 13, 2026
9553eea
wilt: Plan C M5-M8.a — CFG, devirt, inliner_v2, dead-global-writes
gilescope Apr 13, 2026
774ab35
wilt: Plan C M8.b — local dead-code elimination + CFG closer-isolation
gilescope Apr 13, 2026
d8c1132
wilt: M6 phase 2 — single-call-site (T...) -> () inlining
gilescope Apr 13, 2026
98b570b
wilt: const_prop within body — drives the cascade
gilescope Apr 13, 2026
5cea9f1
wilt: hint-aware comparison harness + CFG if/else conditional edges
gilescope Apr 13, 2026
5fc24c0
wilt: branch_threading — fold if/else with constant condition
gilescope Apr 13, 2026
0d34ea8
wilt: M6 phase 3 — inline single-callsite callees that contain return
gilescope Apr 13, 2026
11c1e71
wilt: M6 phase 4 — inline single-callsite (T...) -> R callees
gilescope Apr 13, 2026
5fd3d34
wilt: M6 phase 5 — inline callees that have declared locals
gilescope Apr 13, 2026
70d1acf
wilt: M6 phase 6 — inline callees with internal br/br_if/br_table
gilescope Apr 13, 2026
58eee2a
wilt: M6 phase 7 — inline callees containing call_indirect
gilescope Apr 13, 2026
f54e7e3
wilt: simplify_locals — backward liveness over the CFG (+0.6pp)
gilescope Apr 13, 2026
5609ae0
wilt: fn_merge — dedupe identical-body functions
gilescope Apr 13, 2026
25f707a
wilt: const_prop — forward dataflow over the CFG (cross-BB)
gilescope Apr 13, 2026
39d1dc1
wilt: inliner — multi-callsite with cost model
gilescope Apr 13, 2026
62d5048
wilt: bail-early prechecks for CFG-driven passes (1.5× pipeline speedup)
gilescope Apr 13, 2026
0fd402a
wilt: layout_for_compression — sort fns by body bytes for compressibi…
gilescope Apr 13, 2026
a5f2f83
wilt: copy_prop — CFG-aware local-to-local alias propagation
gilescope Apr 13, 2026
f9548cf
wilt: auto-derive hints in standalone + never-grow guard
gilescope Apr 13, 2026
61b56fd
feat(wilt): add if_fold for identical-branch collapse
gilescope Apr 13, 2026
e51bb55
feat(wilt): LinkerHints::global_const + const_global pass
gilescope Apr 13, 2026
1a70af6
feat(wilt): LinkerHints::func_is_pure + pure_call_elim pass
gilescope Apr 13, 2026
5c878e4
feat(wilt): generalise pure_call_elim to arity n -> k
gilescope Apr 13, 2026
74f2f46
perf(wilt): raise fixpoint cap from 6 to 10 iterations
gilescope Apr 13, 2026
8c8e5d0
feat(wilt): const_fold learns i32 RHS-identity folds
gilescope Apr 13, 2026
99d3b97
feat(wilt): vacuum learns tee+drop -> set peephole
gilescope Apr 13, 2026
1b41b3e
feat(wilt): optimise_stripped() + section_gap diagnostic
gilescope Apr 13, 2026
0ab8ebd
test(wilt): apples-to-apples stripped-vs-stripped comparison
gilescope Apr 13, 2026
ac1e4e6
feat(wilt): vacuum learns 'return before final end' peephole
gilescope Apr 13, 2026
95f7c8c
feat(wilt): precise 0xFC sub-opcode purity in DerivedHints
gilescope Apr 13, 2026
8373949
test(wilt): real_binary harness for compiled-toolchain wasm
gilescope Apr 13, 2026
f373cab
feat(wilt): optimise_stripped matches wasm-opt strip policy
gilescope Apr 13, 2026
0be68d4
fix(wilt): gzip subprocess deadlock on large binaries
gilescope Apr 13, 2026
3d48540
test(wilt): dupe_detect + inline_opportunity diagnostics
gilescope Apr 13, 2026
db9762d
test(wilt): deterministic-output guards
gilescope Apr 13, 2026
7f3eaf2
perf(wilt): fixpoint cap 10 -> 40 + track best-so-far
gilescope Apr 13, 2026
86ca833
feat(wilt): ship wilt CLI binary — drop-in for wasm-opt
gilescope Apr 14, 2026
297aeca
test(wilt): apples-to-apples comparison with debug info preserved
gilescope Apr 14, 2026
1105efa
feat(wilt): Phase 1 — debug-info names tier
gilescope Apr 14, 2026
7977d44
fix(wilt): cap per-function locals in inline_trivial
gilescope Apr 14, 2026
0b8a5f2
feat(wilt): Phase 2a foundation — provenance module
gilescope Apr 14, 2026
214cf28
feat(wilt): Phase 2a start — const_fold emits BodyEdits; MutModule co…
gilescope Apr 14, 2026
d3873b7
feat(wilt): Phase 2a — 5 body-rewriting passes emit BodyEdits
gilescope Apr 14, 2026
9219ab2
feat(wilt): Phase 2a — 5 more passes emit BodyEdits
gilescope Apr 14, 2026
7748caf
feat(wilt): Phase 2a complete — vacuum emits coarse edits
gilescope Apr 14, 2026
f86e29a
feat(wilt): Phase 2b step 1 — Lines tier preserves accurate .debug_line
gilescope Apr 14, 2026
bc9f061
feat(wilt): Phase 2b step 2 — per-function preservation check + offse…
gilescope Apr 14, 2026
a83ecb8
feat(wilt): Phase 2b step 3 — byte-level address patching
gilescope Apr 14, 2026
bc3bd4a
feat(wilt): Phase 2b step 4 — per-sequence splicing
gilescope Apr 14, 2026
7ad1e58
feat(wilt): source-map plumbing — detect, warn-and-strip, CLI flags
gilescope Apr 14, 2026
f6b2674
feat(wilt): source-map step 2 — VLQ mapping transformation
gilescope Apr 14, 2026
964bfa2
feat(wilt): Full debug tier — step 1 preserves .debug_* verbatim
gilescope Apr 14, 2026
0f26998
feat(wilt): Full tier step 2 — patch .debug_ranges + .debug_loc
gilescope Apr 14, 2026
7e8fd24
feat(wilt): Full tier step 3 — patch .debug_aranges
gilescope Apr 14, 2026
2b57985
feat(wilt): Full tier step 4 — .debug_info DIE walker
gilescope Apr 14, 2026
31f3700
feat(wilt): Full tier step 5 — DWARF-5 long tail
gilescope Apr 14, 2026
fddb7d3
feat(wilt): vacuum fine-grained provenance via instruction-diff
gilescope Apr 14, 2026
0de6127
feat(wilt): honour DWARF-64 in all patchers
gilescope Apr 14, 2026
6fec11d
feat(wild): plumb wilt optimiser into the wasm writer behind `-O<N>`
gilescope Apr 14, 2026
1ae9001
feat(wild): route `--strip-*` into wilt's debug-level tier
gilescope Apr 14, 2026
ab4aef4
docs(wilt): document wild's `-O<N>` / `--strip-*` integration
gilescope Apr 14, 2026
89a5111
wip: macOS LTO + ld64-compat, wasm LTO/PIC, incremental cache, test f…
gilescope Apr 22, 2026
6d25034
perf: make as fast as ld64
gilescope Apr 22, 2026
1f8d3b5
refactor(wasm): unify writer with Mach-O via file_writer::Output + Cu…
gilescope Apr 22, 2026
c3a1c98
perf(wilt): defer fixpoint `best` clone until first improvement
gilescope Apr 22, 2026
839bbb8
feat(bench): teach benchmark-runner about wasm
gilescope Apr 22, 2026
ead4bb1
docs(bench): pick concrete wasm workloads (drop ripgrep, add tokei + …
gilescope Apr 22, 2026
0339e36
feat(bench): wasm save-dir builders + capture-link.sh
gilescope Apr 22, 2026
a85e27c
test(wasm): integration test for rustc-driven Rust → wasm link
gilescope Apr 22, 2026
08f3d02
fix(wasm): element-segment init expr must be const under static-PIC
gilescope Apr 22, 2026
480c950
docs(wasm): record investigation breadcrumbs for the type-desync bug
gilescope Apr 22, 2026
2ad5329
fix(wasm): per-input import-index remap + post-shift fixup
gilescope Apr 22, 2026
0715e25
chore: cargo fmt
gilescope Apr 22, 2026
0ef207f
test: gate lld_macho/sold_macho tests on macOS host
gilescope Apr 22, 2026
b489fb6
fix(test): elf duplicate-symbols expectation matches new diagnostic
gilescope Apr 22, 2026
4170143
test(incremental_cache): drift-guard + determinism tests
gilescope Apr 22, 2026
8849fa3
feat(linker): add suffix-sharing strtab packer (phase 1)
gilescope Apr 22, 2026
49b2edb
experiment(size): strtab suffix-sharing post-processor (phase 2a)
gilescope Apr 22, 2026
5b7ba49
experiment(size): zstd-compressed .debug_* sections post-processor
gilescope Apr 22, 2026
d9d0f7b
experiment(recon): cross-CU DIE-dedup upper-bound estimator
gilescope Apr 23, 2026
c52a142
feat(elf): --compress-debug-sections=zstd
gilescope Apr 23, 2026
158444a
feat(elf): add missing elf_compress.rs (fix c52a142)
gilescope Apr 23, 2026
d356151
test(elf_compress): unit tests for zstd post-pass
gilescope Apr 23, 2026
36eff60
test: integration fixture for --compress-debug-sections=zstd
gilescope Apr 23, 2026
001ab44
test: beef up compress-debug-sections fixture, narrow asserts to .deb…
gilescope Apr 23, 2026
b78de3b
test: fixture must return 42 like other wild test programs
gilescope Apr 23, 2026
ed9eb93
experiment(recon): report top duplicate DIE groups + by-tag savings
gilescope Apr 23, 2026
530f6f1
docs: dwarf-size-plan — research + ranked roadmap
gilescope Apr 23, 2026
a718645
docs(dwarf-size-plan): DWARF 4->5 upgrade analysis + debugger-test gate
gilescope Apr 23, 2026
f6adc9a
experiment(test): debugger-roundtrip harness for DWARF rewrite work
gilescope Apr 23, 2026
4e98095
test: ExpectDwarfResolves directive — DWARF correctness gate
gilescope Apr 23, 2026
a83a29c
experiment(recon): .debug_line v4 -> v5 size estimator
gilescope Apr 23, 2026
980cecf
experiment(rewrite): .debug_line v4 -> v5 (phase 2a, no string pool yet)
gilescope Apr 23, 2026
5529b0a
experiment(rewrite): .debug_line v4 -> v5 with .debug_line_str pool (…
gilescope Apr 23, 2026
e352336
feat(elf): -O<N> opt level + --upgrade-debug-line=v5 flag (phase 3a)
gilescope Apr 23, 2026
14a1d8d
feat(elf): wire .debug_line v5 rewriter into wild (phase 3b)
gilescope Apr 23, 2026
6ea73d8
fix(elf_line_v5): only upgrade DWARF 4 line programs; force v4 in tes…
gilescope Apr 23, 2026
9af312e
fix(elf_line_v5): skip rewrite when SHDR is before shstrtab in file
gilescope Apr 23, 2026
212dfb2
feat(elf_line_v5): layout-agnostic splice via op-list (phase 4)
gilescope Apr 23, 2026
8494c46
fix(elf_line_v5): graceful skip when rewrite would grow output
gilescope Apr 23, 2026
7d55d9e
fix(elf_line_v5): move SHDR to end instead of growing in place (phase…
gilescope Apr 23, 2026
570ad0b
fix(compress): respect prior set_final_size from elf_line_v5 (phase 4c)
gilescope Apr 23, 2026
6411876
fix(elf_line_v5): split map_offset into Before/After kinds (phase 4d)
gilescope Apr 24, 2026
c4e9f69
test(elf_line_v5): unit tests for phase 4 bugs
gilescope Apr 24, 2026
cc4ff8e
feat(elf): default --compress-debug-sections=zstd (dwarf-plan #5)
gilescope Apr 24, 2026
8d4a920
feat(elf): .debug_abbrev cross-CU hash-and-collapse (dwarf-plan #3)
gilescope Apr 24, 2026
91aa67e
docs: mark dwarf-plan #3 + #5 as shipped, update -O1 doc
gilescope Apr 24, 2026
19b81bf
bench: add wild -O1/-O2/-O3 columns to the runner
gilescope Apr 24, 2026
298a2ae
bench: accept plain 'GNU ld (GNU Binutils) <ver>' banner
gilescope Apr 24, 2026
0b3fa15
bench: add rust-hello-full entry (full debuginfo sibling)
gilescope Apr 24, 2026
0e5bdd2
fix(lto): restore generic linker-plugin-disabled error message
gilescope Apr 24, 2026
eedebb1
docs: mark dwarf-plan #1 (Mach-O .debug_str dedup) as N/A
gilescope Apr 24, 2026
ade3221
fix(macho): follow 'reexported-libraries:' chains in tbd files
gilescope Apr 24, 2026
64ef599
perf(macho): foldhash for dylib_symbols set — bevy-dylib -9%
gilescope Apr 24, 2026
01f2236
feat(incremental): mmap-backed parsed-input cache format (tier-1 foun…
gilescope Apr 24, 2026
f900907
feat(incremental): atomic write + per-input cache-path derivation
gilescope Apr 24, 2026
315b632
docs: tier-1 parse-skip integration plan
gilescope Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,13 @@ fakes-debug/sde-cet-checker-out.txt
*.bench-results
.DS_Store
*.rcgu.o
.claude/settings.local.json
out/
ld64
# Stray test-run artifacts left in the repo by manual wild invocations.
/wild/*.o
/wild/*.bc
/wild/*.wasm
/wild/a.out
/wild/thinlto-archives/
/wild/d/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
[submodule "wild/tests/bins"]
path = wild/tests/bins
url = https://github.com/wild-linker/test-files
[submodule "external_test_suites/binaryen"]
path = external_test_suites/binaryen
url = https://github.com/WebAssembly/binaryen
215 changes: 202 additions & 13 deletions BENCHMARKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ Follow-these steps:

* Chose the crate that you wish to use in your benchmark, clone it, `cd` into it's root directory
and make sure it builds with `cargo build` (for a rust project)
* Examples: [`ripgrep`](https://github.com/BurntSushi/ripgrep.git)
* Examples: [`ripgrep`](https://github.com/BurntSushi/ripgrep.git)
* Clean the build using `cargo clean`
* To force the build of your chosen crate to link using wild, we have a couple of options:
* Prefix the cargo build command with `RUSTFLAGS="-Clinker=clang -Clink-arg=--ld-path=wild"`
* Modify (or add) the `.cargo/config.toml` file in your chosen crate (example for `ripgrep`)
* Prefix the cargo build command with `RUSTFLAGS="-Clinker=clang -Clink-arg=--ld-path=wild"`
* Modify (or add) the `.cargo/config.toml` file in your chosen crate (example for `ripgrep`)

```toml
[target.x86_64-unknown-linux-gnu]
Expand All @@ -42,11 +42,11 @@ rustflags = ["-Clink-arg=--ld-path=wild"]
* Run `WILD_SAVE_BASE=/tmp/wild/ripgrep cargo build` in the crate's root directory (include
`RUSTFLAGS` as above if you have chosen that method)
* You will get a few numbered subdirectories in `/tmp/wild/ripgrep` as part of the build process.
* Directories will be created for builds of build scripts, proc macros and crate binaries built
* Usually the last numbered subdirectory will be the build of crate's binary (if a single binary
is built)
* You can check what each file is linking using `tail -n 1 /tmp/wild/ripgrep/*/run-with`
* In the case of ripgrep it is '6'
* Directories will be created for builds of build scripts, proc macros and crate binaries built
* Usually the last numbered subdirectory will be the build of crate's binary (if a single binary
is built)
* You can check what each file is linking using `tail -n 1 /tmp/wild/ripgrep/*/run-with`
* In the case of ripgrep it is '6'
* You can then run `/tmp/wild/ripgrep/6/run-with wild` and that will rerun the link with wild

When you run `run-with wild`, the linker may print warnings for unsupported flags. It's a good idea
Expand All @@ -69,15 +69,15 @@ That should produce output similar to this (with different values):
Benchmark 1: /tmp/wild/ripgrep/6/run-with ld
Time (mean ± σ): 954.1 ms ± 13.6 ms [User: 683.4 ms, System: 268.8 ms]
Range (min … max): 920.6 ms … 970.7 ms 10 runs

Benchmark 2: /tmp/wild/ripgrep/6/run-with mold
Time (mean ± σ): 146.1 ms ± 3.6 ms [User: 52.0 ms, System: 2.4 ms]
Range (min … max): 139.1 ms … 154.7 ms 19 runs

Benchmark 3: /tmp/wild/ripgrep/6/run-with wild
Time (mean ± σ): 87.7 ms ± 2.8 ms [User: 2.4 ms, System: 2.0 ms]
Range (min … max): 81.5 ms … 92.5 ms 34 runs

Summary
/tmp/wild/ripgrep/6/run-with wild ran
1.67 ± 0.07 times faster than /tmp/wild/ripgrep/6/run-with mold
Expand Down Expand Up @@ -240,6 +240,195 @@ You should now have a few subdirectories under `/tmp/rustc-link`. You can identi
If the directory `/tmp/rustc-link` didn't get created, then most likely wild wasn't used to
link.

### Benchmarking wild on macOS (Mach-O)

Wild supports Mach-O on aarch64-apple-darwin, and the `benchmark-runner`
crate now understands the `ld64` linker kind so the same harness works
there. The runner filters benchmarks by `platform` — entries default to
`elf` (so every existing `ryzen-9955hx.toml` / `raspberrypi.toml` entry
round-trips unchanged); add `platform = "macho"` to mark a bench as
Mach-O-only.

Smallest end-to-end run (timings below on an M-series host):

```sh
# 1. Build a release wild.
cargo build --release --bin wild

# 2. Capture a wild-linker invocation for a tiny rust bin.
mkdir -p /tmp/wild-saves-macho
cd /tmp && cargo new --bin hello-mac && cd hello-mac
WILD_SAVE_BASE=/tmp/wild-saves/hello-mac \
RUSTFLAGS="-Clinker=clang -Clink-arg=-fuse-ld=$WILD_REPO/target/release/wild" \
cargo build --release
# pick the save-dir that links the binary (tail -n1 of each run-with
# identifies the output path); move it under the bench name:
mv /tmp/wild-saves/hello-mac/0 /tmp/wild-saves-macho/rust-hello-world

# 3. Run the benchmark.
cargo run --release -p benchmark-runner -- \
bench --config benchmarks/macos-arm64.toml \
--saves /tmp/wild-saves-macho \
--tmp /tmp/linker-bench-out \
--allow-non-tmpfs \
$WILD_REPO/target/release/wild /usr/bin/ld

# 4. Produce the report.
cargo run --release -p benchmark-runner -- \
report --config benchmarks/macos-arm64.toml --print-stats
```

Notes on Mach-O specifics:

* `--allow-non-tmpfs` is needed because macOS lacks the tmpfs invariant
the runner enforces on Linux. Writing to a RAM-disk still helps.
* ld64 prints its version to stderr; the runner reads both streams and
parses either `@(#)PROGRAM:ld PROJECT:ld-<ver>` or the legacy
`PROJECT:ld64-<ver>` format.
* `--no-fork` is wild-only on Mach-O (ld64 has no equivalent). The
`peak_rss` figure for ld64 reflects the full process tree.

#### Benchmarking wild's `-ld64_compat` mode

A third `LinkerKind::WildCompat` exists so the report shows wild's
Apple-compat mode (bit-for-bit output against ld64) as a separate bar
alongside default wild and ld64. It is driven by a thin wrapper at
`benchmarks/runner/bin/wild-ld64-compat` that prepends `-ld64_compat`
to every link invocation and rewrites wild's `-v` banner so the runner
tags it distinctly.

```sh
# Point the wrapper at your release wild (or put them in the same dir):
export WILD_BIN=$WILD_REPO/target/release/wild

cargo run --release -p benchmark-runner -- \
bench --config benchmarks/macos-arm64.toml \
--saves /tmp/wild-saves-macho \
--tmp /tmp/linker-bench-out \
--allow-non-tmpfs \
$WILD_BIN \
$WILD_REPO/benchmarks/runner/bin/wild-ld64-compat \
/usr/bin/ld
```

In typical runs `-ld64_compat` costs wild ~5–10 ms of extra link time
but produces smaller output than default-mode wild — matching ld64's
size almost exactly. If you care about bit-for-bit reproducibility
against the Apple toolchain, the cost is negligible.

#### Benchmarking wild at different `-O` levels (ELF only)

`LinkerKind::WildOpt(u8)` exists so the report can graph wild's
`-O0`/`-O1`/`-O2`/`-O3` columns alongside each other and alongside
lld/mold/bfd. Three wrapper scripts at
`benchmarks/runner/bin/wild-O{1,2,3}` prepend the matching `-O<N>`
to every invocation and rewrite the banner (`Wild-O1 …`) so the
runner keeps the columns distinct.

```sh
export WILD_BIN=$WILD_REPO/target/release/wild

cargo run --release -p benchmark-runner -- \
bench --config benchmarks/ryzen-9955hx.toml \
--saves /tmp/wild-saves \
--tmp /tmp/linker-bench-out \
$WILD_BIN \
$WILD_REPO/benchmarks/runner/bin/wild-O1 \
$WILD_REPO/benchmarks/runner/bin/wild-O2 \
$WILD_REPO/benchmarks/runner/bin/wild-O3 \
/usr/bin/ld.lld /usr/bin/mold
```

Today `-O1` enables `.debug_line` v4→v5 + `.debug_abbrev` cross-CU
dedup (SHF_COMPRESSED zstd is on by default since cc4ff8e, so the
`-O0` column already includes it). `-O2` and `-O3` alias to `-O1`
until the heavier passes (suffix-share strtab, cross-CU DIE dedup)
ship. The wrappers are ELF-only — the Mach-O config filter skips
them because libwild's `-O` flag parser lives in `args::elf`.

#### Generating save-dirs for each Mach-O bench

Each entry in `benchmarks/macos-arm64.toml` needs a directory
`/tmp/wild-saves-macho/<bench-name>/run-with` before the runner can
time it. The pattern is always the same: run the workload's native
build with `WILD_SAVE_BASE` + wild as the linker, then move the
numbered subdirectory that links the primary artefact up one level.

`tail -n 1 /tmp/wild-saves/*/run-with` shows which subdirectory links
which output file — pick the one whose artefact matches the bench.

Recipes for the entries currently in the matrix (assumes
`$WILD_REPO=/path/to/wild` and a release-built `$WILD_REPO/target/release/wild`):

```sh
# c-hello-world — trivial C program, noise floor.
mkdir -p /tmp/c-hello && cat > /tmp/c-hello/hello.c <<'EOF'
#include <stdio.h>
int main(void) { puts("hello"); return 0; }
EOF
WILD_SAVE_BASE=/tmp/wild-saves/c-hello-world \
clang -fuse-ld=$WILD_REPO/target/release/wild \
/tmp/c-hello/hello.c -o /tmp/c-hello/hello
mv /tmp/wild-saves/c-hello-world/0 \
/tmp/wild-saves-macho/c-hello-world

# rust-hello-world — `cargo new --bin`, build --release.
cd /tmp && cargo new --bin rust-hello-world && cd rust-hello-world
WILD_SAVE_BASE=/tmp/wild-saves/rust-hello-world \
RUSTFLAGS="-Clinker=clang -Clink-arg=-fuse-ld=$WILD_REPO/target/release/wild" \
cargo build --release
mv /tmp/wild-saves/rust-hello-world/0 \
/tmp/wild-saves-macho/rust-hello-world

# ripgrep — git clone https://github.com/BurntSushi/ripgrep.git, same
# RUSTFLAGS as above, `cargo build --release`. Pick the save-dir
# whose run-with tail links `.../target/release/rg` (usually last).

# bevy-dylib — cd into a bevy-using project, build with
# `--features bevy/dynamic_linking`. The dylib save-dir is the one
# linking `.../libbevy_dylib-*.dylib`.

# rust-analyzer — git clone https://github.com/rust-lang/rust-analyzer.
# Set the RUSTFLAGS globally (via .cargo/config.toml), build with
# `cargo xtask install --server`. Pick the save-dir linking
# `rust-analyzer` itself.

# wild (self-bench) — cd into this repo, build the bin under wild:
cd $WILD_REPO
WILD_SAVE_BASE=/tmp/wild-saves/wild \
RUSTFLAGS="-Clinker=clang -Clink-arg=-fuse-ld=$WILD_REPO/target/release/wild" \
cargo build --release --bin wild
# The save-dir that links .../target/release/wild becomes the bench.
mv /tmp/wild-saves/wild/<N> /tmp/wild-saves-macho/wild

# rust-analyzer-incremental — simulates the inner dev loop (one
# rlib's mtime bumped as if rustc just rebuilt the workload crate).
# Reuses the rust-analyzer save-dir's inputs; only needs a thin
# `run-with` wrapper that touches the main workload rlib before
# exec'ing into rust-analyzer/run-with. Wild has no incremental
# today (README calls it out as the end-goal), so this bench
# currently reads identically to the plain `rust-analyzer` bench
# plus ~25 ms of bash-wrapper overhead (paid equally by every
# linker). The point is to land a named row in the matrix so
# future incremental-linking work shows up as a wall-clock delta
# here rather than being invisible.
mkdir -p /tmp/wild-saves-macho/rust-analyzer-incremental
cat > /tmp/wild-saves-macho/rust-analyzer-incremental/run-with <<'EOF'
#!/usr/bin/env bash
set -e
D=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
for f in $D/../rust-analyzer/private/tmp/rust-analyzer/target/release/deps/librust_analyzer-*.rlib; do
[ -e "$f" ] && touch -h "$f"
done
exec "$D/../rust-analyzer/run-with" "$@"
EOF
chmod +x /tmp/wild-saves-macho/rust-analyzer-incremental/run-with
```

Save-dirs contain absolute paths and are NOT committed to git — they
must be regenerated on each machine. `.gitignore` covers the
`*.bench-results` output files already.

### Other tools

* [poop](https://github.com/andrewrk/poop) - gives a lot of measurements other than just time. Note
Expand All @@ -253,7 +442,7 @@ link.
To figure out where wild is spending time, the first option is to run with `--time`. It's
recommended to combine this with `--no-fork`. For example:

```
```text
~/tmp/rustc-link/0/run-with target/release/wild --strip-debug --time --no-fork
┌─── 3.84 Open input files
├─── 7.45 Split archives
Expand Down Expand Up @@ -362,7 +551,7 @@ Then run the linker on some input. e.g:

This should print some stats on exit. e.g.:

```
```text
dhat: Total: 250,699,127 bytes in 130,224 blocks
dhat: At t-gmax: 111,265,627 bytes in 14,117 blocks
dhat: At t-end: 96,320 bytes in 109 blocks
Expand Down
Loading