Skip to content

fix(tracer): resolve ELF symbol names via the symtab's sh_link - #1877

Merged
0xAndoroid merged 2 commits into
a16z:mainfrom
erkancamli:fix/tracer-symtab-sh-link
Sep 28, 2026
Merged

0xAndoroid merged 2 commits into
a16z:mainfrom
erkancamli:fix/tracer-symtab-sh-link

Conversation

@erkancamli

Copy link
Copy Markdown
Contributor

Summary

Emulator::setup_program resolved every symbol name through the first SHT_STRTAB section in the file (the code carried a @TODO about exactly this assumption). Per the ELF spec, a symbol table's string table is the section named by its sh_link.

GNU ld happens to place .strtab before .shstrtab, so this is invisible with binutils. LLD emits .symtab, .shstrtab, .strtab (checked with clang --target=riscv64 + ld.lld: [5] .symtab Lk=7, [6] .shstrtab, [7] .strtab), so names were read out of .shstrtab and tohost / begin_signature / end_signature were never found.

For jolt-emu this turns a failing arch test into a silent pass: tohost_addr stays 0, run_test polls address 0 (which reads as zero), and the program returns 0 once it stalls on its halt loop, which tests/arch-tests/run.sh counts as a pass. An LLD-linked riscv64 ELF that writes HTIF fail code 3 to tohost exits 0 on main and Test Failed with 3 (exit 1) with this change; the passing variant still exits 0. jolt-emu-x86 duplicated the same lookup and reported no tohost symbol for both.

Changes

  • ElfAnalyzer: expose SectionHeader::sh_link (it was parsed and dropped) and add read_symbol_map, which resolves each SHT_SYMTAB through its own sh_link and skips an out of range link.
  • Emulator::setup_program: use read_symbol_map; drop the two now unused section vectors.
  • jolt-emu-x86 symbol_map: delegate to the same helper instead of its copy of the first-STRTAB lookup.

Testing

  • New emulator::tests::resolves_symbols_through_symtab_sh_link builds a minimal RV64 ELF in code with LLD's section order and asserts tohost resolves (no binary fixture added). It fails on main (left: None, right: Some(0x80001000)) and passes with the fix.
  • Ran tests for modified crates: cargo test -p tracer --lib is 128 passed; the 12 failures are the same with and without this change (they shell out to the jolt CLI to build guests, which is not installed in my environment).
  • cargo clippy -p tracer --all-targets -- -D warnings, cargo clippy -p jolt-tracer-x86 --bins -- -D warnings and cargo fmt --check pass

Security Considerations

Tracer and emulator tooling only; no effect on proving or verification. The fix matters for test harness correctness: with an LLD-built ELF, jolt-emu could report a failing compliance test as passing.

Breaking Changes

None. SectionHeader::sh_link becomes public and ElfAnalyzer::read_symbol_map is added; both are additive.

@github-actions github-actions Bot added the no-spec PR has no spec file label Sep 21, 2026

@0xAndoroid 0xAndoroid left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is right and the bug is real: setup_program picks the first SHT_STRTAB, which under LLD is .shstrtab. Verified on a local merge with current main: the production hunks apply cleanly, the emulator tests plus the new one pass, and clippy is clean for tracer and jolt-tracer-x86.

The branch conflicts with main now (only the new tests module in tracer/src/emulator/mod.rs, which #1697 also added), so it needs a rebase. Two comments to fold into that rebase.

Note: this reply was written by an AI after it reported the issue to me and I made the decision. If anything here is wrong, reply and I will review it myself.

Comment thread tracer/src/emulator/mod.rs Resolved
Comment thread tracer/src/emulator/elf_analyzer.rs Resolved
setup_program resolved every symbol name through the first SHT_STRTAB section. The ELF spec says a symbol table's names live in the section named by its sh_link. LLD emits .symtab, .shstrtab, .strtab, so names were read from .shstrtab and tohost was never found, which made jolt-emu report a failing arch test as a pass. jolt-emu-x86 duplicated the same lookup.
@erkancamli
erkancamli force-pushed the fix/tracer-symtab-sh-link branch from 8bfa904 to 0b978ff Compare September 28, 2026 04:39
@erkancamli

Copy link
Copy Markdown
Contributor Author

Rebased on current main (f830b54), so the conflict is gone, and both comments are folded in. build_elf64 now takes a StrtabOrder (GnuLd / Lld) that swaps the two SHT_STRTAB headers and points .symtab's sh_link and e_shstrndx at the right index; the hand rolled builder is dropped and the LLD case is one more test in the existing module, reusing tohost_program and tohost_symbols. read_symbol_entries takes &[&SectionHeader], so read_symbol_map passes &[symbol_table]. Emulator tests pass, the new case fails if read_symbol_map goes back to the first SHT_STRTAB, and clippy is clean for tracer and jolt-tracer-x86, also with field-inline.

@0xAndoroid 0xAndoroid left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@0xAndoroid
0xAndoroid merged commit 754fc88 into a16z:main Sep 28, 2026
50 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-spec PR has no spec file

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants