Skip to content

[DWARF Import] Fix addresses for PIE and rebased views, relocatable objects and RISC-V objects - #8654

Open
jrozner wants to merge 3 commits into
Vector35:devfrom
jrozner:dwarf-rebase-data-variables
Open

jrozner wants to merge 3 commits into
Vector35:devfrom
jrozner:dwarf-rebase-data-variables

Conversation

@jrozner

@jrozner jrozner commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #8653

DWARF import puts data variables at the wrong address in PIE and rebased views, and in relocatable objects (ET_REL). RISC-V objects built with -g don't import at all. Three commits fix this; each can be reviewed on its own.

1. Rebase data variables like functions

post_process rebases functions by bv.start() - bv.original_image_base() but leaves data variables at their DW_OP_addr addresses. In a PIE, or with a non-default loader.imageBase, every DWARF data variable lands at an unmapped address off by the rebase amount (#8653). Data variables now get the same offset, via a shared rebase_offset helper. Relocatable objects are excluded here; commit 2 handles them.

Binary Variable ELF symbol Before After
globals_pie (view at 0x400000) counter 0x404010 0x4010 0x404010
globals_nopie, loader.imageBase 0x800000 counter 0x804010 0x404010 0x804010

2. Place object file addresses where the view put their sections

All sections of a .o have address 0, so a DWARF address is an offset into the section of its relocation's symbol. The importer only added the image base, so anything outside the first section landed at the wrong address (e.g. 167 functions in zstd's zstd_compress.c all at 0x400000; .bss/.data variables unmapped or missing).

For a relocatable debug file, each allocated section is looked up in the view by name (sizes must match; the ELF view's <name>#<index> duplicates resolve too). RelocationMap::add adds that section's address to relocations against its symbols, so relocated addresses, including .debug_frame, land where the view placed the section. Linked files, the .gnu_debugaltlink file and dwarfdump get an empty map and are unchanged. Objects' data variables are now rebased too. -fcommon symbols have no section and are not relocated.

3. Apply RISC-V label-difference relocations

Any RISC-V object built with -g fails with Failed to parse DWARF: Failed to load DWARF info: Unsupported relocation type: with linker relaxation, GNU as emits ADD/SUB, SET6/SUB6, SET8/SUB8 and SET_ULEB128/SUB_ULEB128 pairs at the same offset, which object can't put in a relocation map. On RISC-V, RelocationMap::add now applies them in file order to a copy of the section data, following the psABI and binutils (perform_relocation; the SUB_ULEB128 addend is ignored, as in binutils PR31179). It errors if a ULEB128 result doesn't fit its encoding or a SET_ULEB128 isn't followed by its SUB_ULEB128. Both labels of a pair are in one section, so the difference doesn't depend on placement.

Testing

Loaded headless with this dwarf_import in place of the bundled one (corePlugins.dwarfImport: false), compared with the importer built from dev:

  • Data variables: the DWARF import: data variable addresses are not rebased in PIE or rebased views #8653 reproducer (gcc 15.2 -g -O0) above; linked x86-64 PIE test program and zstd PIE now match their ELF symbols (5/5 and 46/46, previously 0/5 and 0/46).
  • Objects: x86-64 .o files (-g, -ffunction-sections -fdata-sections, COMDAT, zstd): every function and data variable is on its symbol, also with loader.imageBase 0x800000.
  • RISC-V: an ESP32-C3 corpus (Espressif GCC 14.2, -O2 and -Og) fails before and imports after (20 functions, 2 data variables, 4 types, addresses on their symbols). Names, signatures, locals and types match the same object linked with ld --no-relax.
  • Unchanged: linked non-PIE x86-64 binaries and ESP-IDF hello_world ELFs for the ESP32 and ESP32-C3 give identical results.
  • cargo fmt --check passes; clippy reports the same warnings as dev.

post_process rebases every function address by the view's start minus
the file's original image base, but it left data variables at the
addresses from DW_OP_addr/DW_OP_addrx. When the view isn't at the
original image base (a PIE, which is loaded at 0x400000, or any file
opened with a non-default loader.imageBase), every data variable was
added at an unmapped address off by exactly that amount, and the ELF
symbols at the right addresses got no DWARF type.

Rebase data variables by the same amount, through a helper shared with
the function rebase. Relocatable objects are left as they were: their
addresses are offsets into sections that the view lays out one after
another, so the rebase alone would move their data variables from
unmapped addresses onto other sections' contents, such as code.
…d their sections

Every section of a relocatable ELF object is at address 0, so an address in
its DWARF info is an offset into the section its relocation's symbol is in.
The ELF view lays those sections out one after another from the image base,
but the importer only added the image base, so everything outside the first
section landed in the wrong place: with -ffunction-sections every function
was at the image base, and on Xtensa, where .literal precedes .text, every
function was 0x20 too low.

When the debug file is a relocatable ELF object, look up where the view put
each allocated section and add that to the relocations against symbols in
it. Linked files are unaffected.

With object addresses now relative to the image base like any other file's,
rebase their data variables too, and drop the exception that left them
unrebased.
…tions

Loading a RISC-V relocatable object built with -g failed with "Failed to
load DWARF info: Unsupported relocation type", so no debug info was
imported. object's RelocationMap only accepts absolute relocations, and
with linker relaxation GNU as encodes differences between code labels
as relocation pairs at the same offset: R_RISCV_ADD*/SUB* (high_pc,
line table and FDE lengths), R_RISCV_SET6/SUB6 and SET8/SUB8 (CFA
advances) and R_RISCV_SET_ULEB128/SUB_ULEB128 (location and range list
offsets).

Apply these to the section data before handing it to gimli, in order,
as binutils' perform_relocation does, following the psABI formulas. The
object isn't relaxed, so this gives the right difference. ULEB128 values
keep the length the assembler gave them, and SUB_ULEB128's addend is
ignored like binutils does. R_RISCV_NONE and R_RISCV_RELAX are skipped,
and R_RISCV_32/64 still go through the relocation map, which moves them
to where the view placed their section.

The pairs use the symbols' offsets into their sections as S, without the
section's address in the view: both labels of a pair are in the same
section, so their difference doesn't depend on where it was placed.
@jrozner jrozner changed the title [DWARF Import] Rebase data variable addresses like function addresses [DWARF Import] Fix addresses for PIE and rebased views, relocatable objects and RISC-V objects Oct 13, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DWARF import: data variable addresses are not rebased in PIE or rebased views

1 participant