Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
376 commits
Select commit Hold shift + click to select a range
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
f0120e6
refactor(symbol_db): SymbolSink trait + DefaultSymbolSink
gilescope Apr 24, 2026
87ef10a
feat(incremental): tier-1 parse-skip write path
gilescope Apr 24, 2026
bd38941
feat(incremental): tier-1 parse-skip read + canary paths
gilescope Apr 24, 2026
33a3b43
feat(incremental): gate parse-skip on .wild-hashes cleanness
gilescope Apr 24, 2026
97fe3bf
docs: tier-1 parse-skip canary session 1/3 green on all test sets
gilescope Apr 24, 2026
ef750cd
perf(incremental): parallelize cache pre-fetch in read/canary path
gilescope Apr 24, 2026
88b93c3
docs: tier-1 plan — canary 2/3, parallel cache read landed
gilescope Apr 24, 2026
0541d9a
perf(incremental): drop rename + fan cache writes across rayon
gilescope Apr 24, 2026
de00262
docs: tier-1 parse-skip SHIP-READY — canary 3/3 green, perf table
gilescope Apr 24, 2026
c30ea77
test(incremental): end-to-end parse-skip gate round-trip
gilescope Apr 24, 2026
087c114
perf(incremental): mmap parse-skip cache + parse-skip telemetry
gilescope Apr 24, 2026
7814369
perf(incremental): tier-1.5 — single per-output cache bundle
gilescope Apr 25, 2026
bf8f061
feat(incremental): tier-2 foundation — section-layout snapshot
gilescope Apr 25, 2026
4f430d7
feat(incremental): tier-3 phase 1 — per-section contributors map
gilescope Apr 25, 2026
c37596c
feat(incremental): tier-3 phase 2 — byte-equivalence canary
gilescope Apr 26, 2026
9ce896b
feat(incremental): tier-3 phase 2b — speculative writer-skip
gilescope Apr 26, 2026
6ebc54b
feat(args): --incremental-cache flag (productisation)
gilescope Apr 26, 2026
b265332
docs: INCREMENTAL.md — user-facing guide for --incremental-cache
gilescope Apr 26, 2026
3d5505d
docs: tier-1-plan — record productisation + tier-3 status as of 2026-…
gilescope Apr 26, 2026
d470d1f
feat(incremental): tier-3 phase 3 — partial writer-skip
gilescope Apr 26, 2026
c7e81cc
docs: tier-1-plan — bevy-dylib measurement findings
gilescope Apr 26, 2026
7823430
perf(incremental): tier-3 mmap-COW pre-fill via UpdateInPlace
gilescope Apr 26, 2026
fd0b1ff
perf(macho): SDK cache hits two more code paths — bevy 530→257 ms
gilescope Apr 26, 2026
eabb18a
test(incremental): trait change invalidates dependent rlib
gilescope Apr 26, 2026
4a064bf
feat(incremental): tier-4 — pad alloc sections to 4 KiB on incrementa…
gilescope Apr 26, 2026
d057ec2
feat(daemon): v1 fork-based linker daemon
gilescope Apr 26, 2026
a133f96
feat(daemon): v2 — thin client + in-process opt-in
gilescope Apr 26, 2026
200b1b2
chore: refresh Cargo.lock for wild-client workspace member
gilescope Apr 26, 2026
2d82c16
fix(daemon): in-process re-entrancy via per-request rayon pool
gilescope Apr 26, 2026
de23802
perf(daemon): in-memory SDK/TBD symbol cache for in-process mode
gilescope Apr 26, 2026
45f2d85
perf(daemon): swap DylibSymbols entries to Arc<[u8]>
gilescope Apr 26, 2026
8aa6c09
perf(daemon): session-cache framework lookups + thin-bin profile
gilescope Apr 26, 2026
3c0b742
perf(daemon): replace 50ms drain timeout with O_NONBLOCK read
gilescope Apr 26, 2026
5a15cf8
docs: file wild-on-wild self-link bug
gilescope Apr 26, 2026
a06ec54
debug: deeper wild-on-wild investigation + got_address tracer
gilescope Apr 26, 2026
a578804
fix(macho): drop orphan N_UNDF|N_EXT entries from output symtab
gilescope Apr 27, 2026
0c37c23
debug: investigate parse_cie_aug personality bug, document fix path
gilescope Apr 27, 2026
dfc589d
fix(macho): handle SUBTRACTOR + UNSIGNED CIE personality reloc
gilescope Apr 27, 2026
56519ca
feat(wasm): propagate import LLVM names into name section
gilescope Apr 29, 2026
2110501
test: include OBJC_SELREFS / OBJC_IMAGEINFO in MACHO_SPECIFIC_SECTIONS
gilescope Apr 29, 2026
4eb7324
feat(wasm): emit empty `--import-table` import + unignore 5 tests
gilescope Apr 29, 2026
b02de5f
feat(wasm): cross 100 lld-wasm passing tests
gilescope Apr 29, 2026
9925743
feat(wasm): --keep-section, --page-size, --export triggers archive load
gilescope Apr 29, 2026
0161b74
feat(wasm): synthesize weak-undef function stubs
gilescope Apr 29, 2026
f18160d
feat(wasm): parse --unresolved-symbols=ignore-all and --warn-unresolv…
gilescope Apr 29, 2026
5dbdbb9
feat(wasm): cwd-tracking test runner + ignore-all stub extension
gilescope Apr 29, 2026
bd45948
feat(wasm): resolve more llvm tools, fix -y arg parse, +1 test passing
gilescope Apr 29, 2026
638abba
feat(wasm): synth absolute data symbols + page-size on import-memory
gilescope Apr 29, 2026
7182b74
feat(wasm): user-defs before layout globals, data-sym export synth, sort
gilescope Apr 29, 2026
132f9f4
feat(wasm): --lld-compat flag, export-all.s byte-for-byte parity
gilescope Apr 29, 2026
da53bc7
feat(wasm): mutable-globals feature flag + skip Data pseudo-syms
gilescope Apr 29, 2026
7f7cf49
feat(wasm): -y / --trace-symbol and --print-gc-sections diagnostics
gilescope Apr 29, 2026
566d92e
feat(wasm): --why-extract / archive-resolution edge tracking
gilescope Apr 30, 2026
c4fc1a3
fix(wasm): -wrap parsing, weak-undef GOT zero, PIE GOT pass-through
gilescope Apr 30, 2026
c40c0f3
feat(wasm): --why-extract polish (-u/-e source labels, error format)
gilescope Apr 30, 2026
8d5aa28
feat(wasm): GC-aware undef-symbol error path; --import-undefined
gilescope Apr 30, 2026
87f8b3e
feat(wasm): sig-mismatch trap stubs (exec) and wasm-export-name attri…
gilescope Apr 30, 2026
288bc75
feat(wasm): --wrap NAME body rewrite (Phase 1c)
gilescope Apr 30, 2026
b0bb14f
docs(wasm-link): record Phase 1 completion and Phase 2/3 reality check
gilescope Apr 30, 2026
752f083
feat(wasm): -M / -Map=PATH / -print-map link map (Phase 2 partial)
gilescope Apr 30, 2026
c5a4897
feat(wasm): map-file GLOBAL/DATA sub-rows + R_WASM_TABLE_INDEX_I32 in…
gilescope Apr 30, 2026
e428bee
docs(wasm-link): record Phase 2 partial-ship status
gilescope Apr 30, 2026
a5194fa
feat(wasm): 8-byte align __llvm_covfun chunks across inputs
gilescope May 1, 2026
6dfd906
feat(wasm): -t / --trace prints loaded input file paths
gilescope May 1, 2026
a46c700
feat(wasm): -v / -V / --version print "LLD <version>"
gilescope May 1, 2026
f5dd69f
docs(wasm-link): record targeted wins beyond Phase 1
gilescope May 1, 2026
942bff4
docs(wasm-link): document archive-resolution dead-path issue
gilescope May 1, 2026
34001f1
feat(wasm): Phase 3a — command_export wrapper + init-func source-obje…
gilescope May 1, 2026
c87e804
feat(wasm): WASM_SYM_EXPORTED command_export wrappers
gilescope May 1, 2026
85d2a80
fix(wasm): skip command_export wrapper when ctors body is empty
gilescope May 1, 2026
20008e0
docs(wasm-link): mark Phase 3a complete
gilescope May 1, 2026
d314a3f
feat(wasm): --whole-archive members are unconditionally alive in init…
gilescope May 1, 2026
33c3ed2
docs(wasm-link): bump test count to 132 (Phase 3a + whole-archive fix)
gilescope May 1, 2026
352890d
feat(wasm): Phase 3b PIE PIC-base imports
gilescope May 1, 2026
eb29a5a
feat(wasm): Phase 4a partial — per-input EXPORT-emit-order
gilescope May 1, 2026
be3181a
feat(wasm): Phase 4b partial — shared library .so resolution
gilescope May 1, 2026
ba55a3a
feat(wasm): widen dylink.0 emit gate to PIE and Bdynamic exec links
gilescope May 1, 2026
455a16c
feat(wasm): skip .so symbols at platform-shared symbol_db layer
gilescope May 1, 2026
9df8395
feat(wasm): conditional shared/PIE imports + correct memory min
gilescope May 1, 2026
dc07e11
feat(wasm): list local-symbols in KNOWN_PASSING
gilescope May 1, 2026
15b13b5
feat(wasm): dylink.0 ImportInfo + table tracking under shared/PIE
gilescope May 1, 2026
ff76408
feat(wasm): memory64 widening for table + GOT.* imports
gilescope May 1, 2026
4734fb9
docs(wasm-link): bump test count to 140 + summarise remaining work
gilescope May 1, 2026
38b9fcf
feat(wasm): accept --unresolved-symbols=import-dynamic + --noinhibit-…
gilescope May 1, 2026
06c1549
feat(wasm): segment-name carry-through + -Bsymbolic warning
gilescope May 1, 2026
0def392
feat(wasm): rpath → dylink.0 RuntimePath subsection
gilescope May 1, 2026
2ead7b4
fix(wasm): soft-skip out-of-bounds call-operand patches
gilescope May 1, 2026
c4763fe
docs(wasm-link): bump tally to 141 + summarise session-end state
gilescope May 1, 2026
5082397
feat(wasm): function_export_pos scaffolding for Phase 4a metadata
gilescope May 4, 2026
56ba9c1
docs(wasm-link): record Phase 4a investigation findings
gilescope May 4, 2026
95c5c5f
feat(wasm): EXPORT-sort kind tiebreak with three GLOBAL classes
gilescope May 5, 2026
a26e912
fix(wasm): BINDING_LOCAL multi-def — bypass cross-input name lookup
gilescope May 5, 2026
f873350
feat(wasm): demangle `name` custom section's FunctionNames entries
gilescope May 5, 2026
4357aa5
fix(wasm): map-file CODE/DATA virtual offsets + full input path
gilescope May 5, 2026
15f2aed
feat(wasm): --noinhibit-exec emits per-collision warning
gilescope May 5, 2026
4065169
fix(wasm): suppress __wasm_call_ctors from --export-dynamic + accept …
gilescope May 5, 2026
4a78751
docs(wasm-link): bump tally to 144 + log session-end status
gilescope May 5, 2026
595a4b5
feat(wasm): GC unreferenced function/global imports
gilescope May 5, 2026
a2bfd2e
docs(wasm-link): bump tally to 145 + log gc_imports + Phase 4a hint
gilescope May 5, 2026
03d6bd5
feat(incremental): --emit-patch=<path> writes byte-diff for AOT EnC
gilescope May 5, 2026
aa10ac1
feat(emit-patch): bump format to v2 with inline pre-image bytes
gilescope May 5, 2026
884f022
feat(macho): ObjC pipeline + cross-dylib TLV + two-level namespace binds
gilescope May 5, 2026
c45ed90
docs(macho): mark merge-scope / order-file / objc plans as DONE
gilescope May 5, 2026
d177653
feat(emit-patch): bump format to v3 with blake3 + per-symbol attribution
gilescope May 5, 2026
2ec0896
experiment(hot-reload): cdylib plugin + libloading host
gilescope May 5, 2026
d83199f
chore; rust fmt
gilescope May 9, 2026
66443cf
Support emit-patch baseline diagnostics
gilescope May 9, 2026
ceace53
Use named N_TYPE/N_SECT mach-o constants in stab synthesis
gilescope May 10, 2026
c251c2e
emit-patch: filter __LINKEDIT byte runs + tests
gilescope May 10, 2026
869868b
emit-patch: cargo fmt
gilescope May 10, 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
  •  
  •  
  •  
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/target
/target2
/bench-fixtures
sample-link*
*.strace
flamegraph.svg
Expand All @@ -24,3 +25,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