Skip to content

link(ELF): empty loaded sections get section headers at address 0 / offset 0, and every dynamic x86-64 executable carries an empty PT_TLS #1727

Description

@davidgmbb

Summary

Low severity; the loader is unaffected. Two ELF image facts that tools misreport:

  1. link_elf_section_table_append emits a header for every kind in link_elf_loaded_kinds (.text .rodata .data .bss .tdata .tbss .eh_frame). An empty one gets sh_addr = 0 and sh_offset = 0 (the descriptor sets .address = size ? image_base + offset : 0). readelf therefore places those sections in whichever segment covers address 0, e.g. a zero-sized PT_GNU_STACK, or the first PT_LOAD of an ET_DYN image at base zero.
  2. link_native_executable_elf64_x86_64_dynamic always writes a PT_TLS program header, with zero sizes when the program has no thread-local storage. GNU ld emits none. The link/driver: shared objects and PIEs for x86-64 Linux (#1604) #1712 position-independent writer emits PT_TLS only when there is TLS.

Revision

Main 76a7bdd377e8769ebbb98d1cc178561b8d88c1a6, and branch claude/eloquent-dijkstra-4dnltv commit 686c379 (unchanged there). x86_64 Linux, Clang 18.1.3 Release ide, GNU Binutils 2.42.

Reproduction

int main(void) { return 3; }
$ ide cc -g0 static.c -o prog && readelf -lSW prog
  [ 2] .rodata   PROGBITS  0000000000000000 000000 000000 00   A  0 0 16
  [ 3] .data     PROGBITS  0000000000000000 000000 000000 00  WA  0 0 16
  [ 4] .bss      NOBITS    0000000000000000 000000 000000 00  WA  0 0 16
  [ 5] .tdata    PROGBITS  0000000000000000 000000 000000 00 WAT  0 0 16
  [ 6] .tbss     NOBITS    0000000000000000 000000 000000 00 WAT  0 0 16
 Section to Segment mapping:
   05                       <- the empty PT_TLS
   07     .rodata .data .bss   <- PT_GNU_STACK (vaddr 0, size 0)

An ET_DYN from ide cc -shared shows the same thing with the empty .bss listed in the text segment.

Expected

  • Empty loaded sections either get no header, as GNU ld discards them, or keep an address and offset inside their segment.
  • No PT_TLS is written without thread-local data.

The image's bytes, program headers and loader behaviour are otherwise unaffected. Only section-based consumers (readelf, objdump, debuggers mapping addresses to sections) see these entries.

Done when

readelf -lSW on the fixed-address, dynamic and #1712 position-independent images lists no section at address 0, and no zero-sized PT_TLS appears. A test checks both on one static-shaped and one dynamic image.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions