gccldlinker-scriptsreadelfarm-none-eabi-gcc

Duplicate section VMAs of 0 in default linker script


arm-none-eabi-gcc's default linker script defines several sections with VMA of 0. Most of these contain debug information:

  /* Stabs debugging sections.  */
  .stab          0 : { *(.stab) }
  .stabstr       0 : { *(.stabstr) }
  .stab.excl     0 : { *(.stab.excl) }
  .stab.exclstr  0 : { *(.stab.exclstr) }
  .stab.index    0 : { *(.stab.index) }
  .stab.indexstr 0 : { *(.stab.indexstr) }
  .comment       0 : { *(.comment) }
  .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
  /* DWARF debug sections.
     Symbols in the DWARF debugging sections are relative to the beginning
     of the section so we begin them at 0.  */
  /* DWARF 1.  */
  .debug          0 : { *(.debug) }
  .line           0 : { *(.line) }
  /* GNU DWARF 1 extensions.  */
  .debug_srcinfo  0 : { *(.debug_srcinfo) }
  .debug_sfnames  0 : { *(.debug_sfnames) }
  /* DWARF 1.1 and DWARF 2.  */
  .debug_aranges  0 : { *(.debug_aranges) }
  .debug_pubnames 0 : { *(.debug_pubnames) }
  /* DWARF 2.  */
  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
  .debug_abbrev   0 : { *(.debug_abbrev) }
  .debug_line     0 : { *(.debug_line .debug_line.* .debug_line_end) }
  .debug_frame    0 : { *(.debug_frame) }
  .debug_str      0 : { *(.debug_str) }
  .debug_loc      0 : { *(.debug_loc) }
  .debug_macinfo  0 : { *(.debug_macinfo) }

  //snip several more of these, until...

  .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
  .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }

I don't understand what this does, and the explanatory comment on the DWARF sections doesn't help - the sections can't really all have the same start address unless they're all size 0! Plus, the script is assigning address 0 to the sections, not the symbols. And that comment didn't apply to the "Stabs" section...

Using readelf -S shows that they all theoretically have an address of 0, but also all have different offsets - presumably these offsets are their actual addresses if loaded:

  [13] .stab             PROGBITS        00000000 009a6c 00009c 0c     14   0  4
  [14] .stabstr          STRTAB          00000000 009b08 00014d 00      0   0  1
 
   ...

  [16] .debug_aranges    PROGBITS        00000000 009cb0 0005f0 00      0   0  8
  [17] .debug_info       PROGBITS        00000000 00a2a0 0110c9 00      0   0  1
  [18] .debug_abbrev     PROGBITS        00000000 01b369 00401d 00      0   0  1
  [19] .debug_line       PROGBITS        00000000 01f386 0063ed 00      0   0  1
  [20] .debug_frame      PROGBITS        00000000 025774 00097c 00      0   0  4
  [21] .debug_str        PROGBITS        00000000 0260f0 001f29 01  MS  0   0  1
  [22] .debug_line_str   PROGBITS        00000000 028019 0000b3 01  MS  0   0  1
  [23] .debug_loclists   PROGBITS        00000000 0280cc 00221c 00      0   0  1
  [24] .debug_rnglists   PROGBITS        00000000 02a2e8 000495 00      0   0  1
  [25] .ARM.attributes   ARM_ATTRIBUTES  00000000 02a77d 00002e 00      0   0  1

The only idea I have is that virtual address 0 might be considered a special address, which is not taken literally, but instead means that sections with this address will not be loaded into memory (and so will not have a load address) unless the code is being run under a debugger. I have not been able to find any evidence to support this, however.

Can anyone explain to me what is actually happening with these duplicate addresses?


Solution

  • This is explained in the elf(5) man page:

      sh_flags
              ...
              SHF_ALLOC
                     This section occupies memory during process
                     execution.  Some control sections do not reside in
                     the memory image of an object file.  This attribute
                     is off for those sections.
       sh_addr
              If this section appears in the memory image of a process,
              this member holds the address at which the section's first
              byte should reside.  Otherwise, the member contains zero.
    

    You should see that the SHF_ALLOC flag is unset for those sections (no A in the Flags field of the readelf -S output) and so they do not reside in the memory image. There is thus no need to specify a start address, so that field is set to zero.

    These sections actually do not need to be loaded into memory by exec* under any circumstances, debugger or not. They are certainly not needed for the programmer to run, and when debugging, the debugger will open and read the binary file to parse out that data, as a separate operation from executing the program.