Skip to content

Emit correct ELF symbol types for data in NativeAOT objects#129950

Merged
max-charlamb merged 1 commit into
mainfrom
max-charlamb/naot-elf-symbol-types
Jun 28, 2026
Merged

Emit correct ELF symbol types for data in NativeAOT objects#129950
max-charlamb merged 1 commit into
mainfrom
max-charlamb/naot-elf-symbol-types

Conversation

@max-charlamb

Copy link
Copy Markdown
Member

Summary

ElfObjectWriter.EmitSymbolTable classified every defined symbol purely by size:

definition.Size > 0 ? STT_FUNC : STT_NOTYPE;

This produced two wrong results for data symbols:

  1. Vtables emitted as STT_NOTYPE. A MethodTable/EEType symbol points at a non-zero offset within its node (the EEType sits after the GCDesc), so Size == 0 and it became STT_NOTYPE. Released lldb only infers a type for NOTYPE symbols whose section name is in a hard-coded list (.text/.data/.rodata/.bss); symbols in other allocated sections such as .hydrated (the NOBITS region that rehydrated data structures live in when data dehydration is enabled) stay untyped and are not surfaced in lldb symbol lookup. Tools that read st_info directly (gdb, nm, addr2line, perf) never see a type at all.
  2. Data emitted as STT_FUNC. Data symbols with Size > 0 in .rodata/.data were marked STT_FUNC, i.e. data mislabeled as code (lldb then treats them as functions).

Fix

Classify by section kind instead of size:

(section.SectionHeader.Flags & SHF_TLS) == SHF_TLS ? STT_TLS :
(section.SectionHeader.Flags & SHF_EXECINSTR) != SHF_EXECINSTR ? STT_OBJECT :
definition.Size > 0 ? STT_FUNC : STT_NOTYPE;

Non-executable sections emit STT_OBJECT; executable sections keep the existing STT_FUNC/STT_NOTYPE behavior unchanged. This matches the canonical typing every other ELF producer uses and is size-neutral (only the st_info type byte changes).

Validation

Cross-emitted a Linux x64 object (--targetos:linux, dehydration on) before/after the change from an otherwise identical toolchain. Object size is byte-identical (3,555,456 bytes).

Section Before After
.hydrated (NOBITS, vtables) 1084 NOTYPE + 377 FUNC 1461 OBJECT
.rodata 245 FUNC (+2 NOTYPE) 247 OBJECT
.data 338 FUNC 338 OBJECT
.text (code) 83 FUNC 83 FUNC (unchanged)

Executable-section symbols are untouched, so ARM/AArch64/RISC-V mapping symbols ($a/$d/$x) and trampolines are unaffected.

Note

This PR description was generated with the assistance of GitHub Copilot.

ElfObjectWriter classified defined symbols solely by size
(Size > 0 ? STT_FUNC : STT_NOTYPE). This had two problems:

- Data symbols pointing at a non-zero offset within their node
  (e.g. MethodTable/EEType vtables, which sit after the GCDesc) get
  Size == 0, so they were emitted as STT_NOTYPE. Released lldb only
  infers a type for NOTYPE symbols in a hard-coded set of section
  names (.text/.data/.rodata/.bss); symbols in other allocated
  sections such as .hydrated stay untyped and are not surfaced in
  symbol lookup.
- Data symbols with Size > 0 in .rodata/.data were emitted as
  STT_FUNC, i.e. data mislabeled as code.

Classify by section instead: non-executable sections emit STT_OBJECT,
executable sections keep the existing STT_FUNC/STT_NOTYPE behavior.
This is the canonical typing other ELF producers use, helps every
consumer that reads st_info directly (lldb, gdb, nm, addr2line, perf),
and is size-neutral. Executable-section symbols are unchanged, so
ARM/AArch64/RISC-V mapping symbols and trampolines are unaffected.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates NativeAOT’s ELF object writer symbol-table emission to choose ELF symbol types based on section flags (TLS / executable vs non-executable), rather than inferring type from symbol size alone.

Changes:

  • Adjust symbol classification in ElfObjectWriter.EmitSymbolTable to emit STT_OBJECT for defined symbols in non-executable sections.
  • Preserve existing STT_FUNC/STT_NOTYPE behavior for executable sections and keep STT_TLS for TLS sections.

@max-charlamb max-charlamb marked this pull request as ready for review June 28, 2026 19:09
@max-charlamb max-charlamb requested a review from Copilot June 28, 2026 19:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@max-charlamb max-charlamb merged commit 0d3df07 into main Jun 28, 2026
114 of 115 checks passed
@max-charlamb max-charlamb deleted the max-charlamb/naot-elf-symbol-types branch June 28, 2026 23:38
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview7 milestone Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants