Skip to content

Extra PHDR section header in dbg file built via --separate-debug-file #1535

@akarle

Description

@akarle

First as always, a big thank you for all the hard work on mold. The performance gains have been incredibly impressive, especially with --separate-debug-file in a slower IO environment.

@mgulick and I noticed that gdb was significantly slower at symbol resolution with mold when we use --separate-debug-file, and while we're still looking into exactly what's going on in gdb, the thing that seems to stand out most is that there is this PHDR section header in the .dbg file that seems out of place (our best guess right now is that gdb chokes on it and starts searching the wrong section for symbols).

I've tried poking around the mold source code and see PHDR is a special "synthetic" chunk name that is intended to represent the Program Header, so it feels unintentional that it's being written into the section header (especially given its not there without --separate-debug-file), but I could be misunderstanding its purpose.

Can you confirm whether it's presence is expected? If it is, we can keep digging and hopefully get to a bug report for gdb.


Here's my minimal reproducer on Debian 12.12 using the latest mold commit (fcd5391) and gcc 12.2.0-14+deb12u1. Note that it seems somewhat sporadic for reasons I can't determine, so if it doesn't appear the first time you may need to relink a couple times.

$ cat foo.c
#include <stdio.h>
int foo(int f) {
  puts("hello world");
  return f + 1;
}

$ cat main.c
int foo(int);
int main() {
    return foo(0);
}

cc -g -O0 -c -fPIC foo.c
cc -fuse-ld=mold -Wl,--separate-debug-file -shared -o libfooBAD.so foo.o
cc -g -O0 main.c -o bad -L. -lfooBAD -Wl,-rpath -Wl,'$ORIGIN'

cc -fuse-ld=mold -shared -o libfooGOOD.so foo.o
objcopy --only-keep-debug libfooGOOD.so libfooGOOD.so.dbg
strip libfooGOOD.so
objcopy --add-gnu-debuglink=libfooGOOD.so.dbg libfooGOOD.so
cc -g -O0 main.c -o good -L. -lfooGOOD -Wl,-rpath -Wl,'$ORIGIN'

readelf -SW libfooBAD.so.dbg | grep PHDR
  [ 1] PHDR              NOBITS          0000000000000040 000040 000230 00   A  0   0  8

readelf -SW libfooGOOD.so.dbg | grep PHDR
[empty]

And here's the full symbol table

$ readelf -SW libfooBAD.so.dbg
There are 38 section headers, starting at offset 0x4a8:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] PHDR              NOBITS          0000000000000040 000040 000230 00   A  0   0  8
  [ 2] .note.gnu.build-id NOTE            0000000000000270 000270 000024 00   A  0   0  4
  [ 3] .gnu.hash         NOBITS          0000000000000298 000294 000020 00   A  3   0  8
  [ 4] .dynsym           NOBITS          00000000000002b8 000294 0000a8 18   A  4   1  8
  [ 5] .dynstr           NOBITS          0000000000000360 000294 000076 00   A  0   0  1
  [ 6] .gnu.version      NOBITS          00000000000003d6 000294 00000e 02   A  3   0  2
  [ 7] .gnu.version_r    NOBITS          00000000000003e4 000294 000020 00   A  4   1  4
  [ 8] .rela.dyn         NOBITS          0000000000000408 000294 0000a8 18   A  3   0  8
  [ 9] .rela.plt         NOBITS          00000000000004b0 000294 000018 18   A  3  23  8
  [10] .eh_frame         NOBITS          00000000000004c8 000294 00003c 00   A  0   0  8
  [11] .eh_frame_hdr     NOBITS          0000000000000504 000294 000014 00   A  0   0  4
  [12] .rodata           NOBITS          0000000000000518 000294 000031 00   A  0   0  8
  [13] .fini             NOBITS          000000000000154c 000294 000009 00  AX  0   0  4
  [14] .init             NOBITS          0000000000001558 000294 000017 00  AX  0   0  4
  [15] .plt              NOBITS          0000000000001570 000294 000030 00  AX  0   0 16
  [16] .plt.got          NOBITS          00000000000015a0 000294 000008 00  AX  0   0 16
  [17] .text             NOBITS          00000000000015b0 000294 0000ee 00  AX  0   0 16
  [18] .dynamic          NOBITS          00000000000026a0 000294 0001c0 10  WA  4   0  8
  [19] .fini_array       NOBITS          0000000000002860 000294 000008 00  WA  0   0  8
  [20] .init_array       NOBITS          0000000000002868 000294 000008 00  WA  0   0  8
  [21] .got              NOBITS          0000000000002870 000294 000028 00  WA  0   0  8
  [22] .relro_padding    NOBITS          0000000000002898 000294 000768 00  WA  0   0  1
  [23] .data             NOBITS          0000000000003000 000294 000008 00  WA  0   0  8
  [24] .got.plt          NOBITS          0000000000003008 000294 000020 00  WA  0   0  8
  [25] .tm_clone_table   NOBITS          0000000000003028 000294 000000 00  WA  0   0  8
  [26] .bss              NOBITS          0000000000003028 000294 000001 00  WA  0   0  1
  [27] .comment          NOBITS          0000000000000000 000294 000077 01  MS  0   0  1
  [28] .gnu_debuglink    NOBITS          0000000000000000 00030c 000018 00      0   0  4
  [29] .shstrtab         STRTAB          0000000000000000 000324 00017e 00      0   0  1
  [30] .debug_abbrev     PROGBITS        0000000000000000 000e28 00009a 00      0   0  1
  [31] .debug_aranges    PROGBITS        0000000000000000 000ec2 000030 00      0   0  1
  [32] .debug_info       PROGBITS        0000000000000000 000ef2 0000cc 00      0   0  1
  [33] .debug_line       PROGBITS        0000000000000000 000fbe 00005f 00      0   0  1
  [34] .debug_line_str   PROGBITS        0000000000000000 00101d 00004f 01  MS  0   0  1
  [35] .debug_str        PROGBITS        0000000000000000 00106c 0000c1 01  MS  0   0  1
  [36] .strtab           STRTAB          0000000000000000 00112d 0002bd 00      0   0  1
  [37] .symtab           SYMTAB          0000000000000000 0013f0 0007f8 18     36  79  8
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  D (mbind), l (large), p (processor specific)

the program header on the debug info is also nulled out:

$ readelf -a libfooBAD.so.dbg

...
Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0
  NULL           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000         0x0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions