I was trying to produce a simple, fully statically linked binary so that it can easily run on distributions such as Alpine without having to install anything else. In my use case, I'm only using a couple of header only libraries, namely fmt and spdlog.
Let's say I want to compile the following file into a fully-static binary:
#define FMT_HEADER_ONLY
#define SPDLOG_FMT_EXTERNAL
#include <fmt/core.h>
#include <spdlog/spdlog.h>
int main(int argc, char* argv[]) {
fmt::print("Hello, {}!\n", "fmt");
spdlog::info("Hello, {}!", "spdlog");
return 0;
}
If I use the following command, I get the expected result:
g++ test.cpp -o out -O3 -fuse-ld=gold -static # Compiles correctly
ldd out # not a dynamic executable
./out # Prints the expected output
But looking at some practices to reduce the binary size, and since it is what the Bazel optimized build does by default, I would like to like to pass the -gc-sections
flag to the linker.
The problem is that, when I do
g++ test.cpp -o out -O3 -fuse-ld=gold -Wl,-gc-sections -static
I get the following error:
/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib/libc.a(pthread_create.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib/libc.a(pthread_create.o)(.note.stapsdt+0x74): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
collect2: error: ld returned 1 exit status
Playing around a bit with different combinations (trying different linkers, adding and removing flags) I obtained the following table:
-fuse-ld |
-Wl,-gc-sections |
Binary size |
---|---|---|
bfd | Yes | 2.0M |
bfd | No | 2.5M |
gold | Yes | ERROR |
gold | No | 2.5M |
So, it is clear that I could either remove the flag and still use the gold linker or just use another linker. I could also just give up on statically linking everything.
What I'm interested in is understanding why I get that error. Is it something I'm doing wrong, I'm missing something or is it a bug in gold?
Additional information:
What I'm interested in is understanding why I get that error. Is it something I'm doing wrong, I'm missing something or is it a bug in gold?
You aren't missing anything (at least nothing relevant to the linkage failure)
and aren't doing anything wrong. There is a corner-case bug in ld.gold
.
Repro
I have your progam source in test.cpp
. I haven't installed the header-only libraries
spdlog
or fmt
; I've just cloned the repos for the present purpose.
$ g++ --version | head -n1
g++ (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0
$ ld.gold --version | head -n1
GNU gold (GNU Binutils for Ubuntu 2.42) 1.16
$ export CPATH=$HOME/develop/spdlog/include:$HOME/develop/fmt/include
$ g++ -c test.cpp
Link without -gc-sections
:
$ g++ test.o -fuse-ld=gold -static; echo Done
Done
And with -gc-sections
:
$ g++ test.o -fuse-ld=gold -static -Wl,-gc-sections; echo Done
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x74): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
collect2: error: ld returned 1 exit status
Done
Trying other linkers
Besides gold
, -fuse-ld
recognises three other ELF linkers. Let's try them all at
that linkage:
ld.bfd (the default GNU linker)
$ ld.bfd --version | head -n1
GNU ld (GNU Binutils for Ubuntu) 2.42
$ g++ test.o -fuse-ld=bfd -static -Wl,-gc-sections
$ ./a.out
Hello, fmt!
[2025-05-06 18:17:10.378] [info] Hello, spdlog!
ld.lld (the LLVM linker)
$ ld.lld --version | head -n1
Ubuntu LLD 18.1.6 (compatible with GNU linkers)
$ g++ test.o -fuse-ld=lld -static -Wl,-gc-sections
$ ./a.out
Hello, fmt!
[2025-05-06 18:18:21.994] [info] Hello, spdlog!
ld.mold (the Modern linker)
$ ld.mold --version | head -n1
mold 2.30.0 (compatible with GNU ld)
$ g++ test.o -fuse-ld=mold -static -Wl,-gc-sections
$ ./a.out
Hello, fmt!
[2025-05-06 18:22:47.597] [info] Hello, spdlog!
So gold
is the only one that can't link this program.
What is gold
doing wrong?
The first diagnostic:
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x14): \
error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
is reporting that the relocation target at offset 0x14 in section .note.stapsdt
of object file
libc.a(pthread_create.o)
refers to the local symbol .text
, which is symbol #1 in that object
file, and that this relocation can't be carried out because the section in which that symbol is
defined has been discarded.
The second diagnostic is the just same, except that the relocation target this time is at offset 0x74, so we'll just pursue the first diagnostic.
Let's check that it's true.
First get that object file:
$ ar -x $(realpath /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a) pthread_create.o
Check out the relocations for its note.stapsdt
section:
$ readelf -rW pthread_create.o
...[cut]...
Relocation section '.rela.note.stapsdt' at offset 0x46f8 contains 4 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
0000000000000014 0000000100000001 R_X86_64_64 0000000000000000 .text + 40e
000000000000001c 0000003000000001 R_X86_64_64 0000000000000000 _.stapsdt.base + 0
0000000000000074 0000000100000001 R_X86_64_64 0000000000000000 .text + c7b
000000000000007c 0000003000000001 R_X86_64_64 0000000000000000 _.stapsdt.base + 0
...[cut]...
Yes, it has relocation targets at offset 0x14 and 0x74. The first one is to be patched using the address
of symbol # 1 ( = Info >> 32) in the symbol table (which we're told is .text
) + 0x40e. Symbol #1 in pthread_create.o
is
$ readelf -sW pthread_create.o | grep ' 1:'
1: 0000000000000000 0 SECTION LOCAL DEFAULT 2 .text
indeed local symbol .text
, (a section name) and it is defined in section #2 of the file
which of course is:
$ readelf -SW pthread_create.o | grep ' 2]'
[ 2] .text PROGBITS 0000000000000000 000050 001750 00 AX 0 0 16
the .text
section.
So the diagnostic reports that gold
has binned the .text
section of pthread_create.o
. Let's
ask gold to tell us what sections of pthread_create.o
it discarded.
$ g++ test.o -fuse-ld=gold -static -Wl,-gc-sections,-print-gc-sections 2>&1 | grep pthread_create.o
/usr/bin/ld.gold: removing unused section from '.text' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.bss' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.rodata.str1.1' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.rodata.str1.8' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.text.unlikely' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.rodata.str1.16' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.rodata.cst4' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.rodata' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.gold: removing unused section from '.rodata.cst8' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x74): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
It discarded 10 of the:
$ readelf -SW pthread_create.o | head -n1
There are 23 section headers, starting at offset 0x48c0:
23 sections in the file, including .text
, as compared with:
$ g++ test.o -fuse-ld=bfd -static -Wl,-gc-sections,-print-gc-sections 2>&1 | grep pthread_create.o
/usr/bin/ld.bfd: removing unused section '.group' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.bfd: removing unused section '.stapsdt.base[.stapsdt.base]' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.bfd: removing unused section '.rodata.cst4' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
/usr/bin/ld.bfd: removing unused section '.rodata' in file '/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)'
the 4 sections discarded by ld.bfd
, excluding .text
. gold
also retains 2 sections (.group
,stapsdt.base
) that bfd
discards, but the outcome
says that gold
has chucked out a baby with the bathwater.
The linkage error is a (all but) a false alarm
The retention of section .note.stapsdt
from pthread_create.o
sets it off. This
section is retained because any output .note.*
section will be a GC-root section for
any linker: .note
sections are conventionally reserved for special information to
be consumed by other programs, and as such are unconditionaally retained in the same
way as ones defining external symbols. note.stapsdt
sections in particular are emitted to expose
patch points for the runtime insertion of Systemtap
instrumentation hooks.
Presumably, you don't care if this program has Systemtap support. You've just got
it because it's compiled into pthread_create.o
(and elsewhere in GLIBC). The
enabling .note.stapsdt
section it a GC-root section in pthread_create.o
that
references its .text
section. But your program has no functional need for that
.text
section. We can observe this by just blowing through the linkage failure
with:
$ rm a.out
$ g++ test.o -fuse-ld=gold -static -Wl,-gc-sections,--noinhibit-exec
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x74): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
--noinhibit-exec
tells the linker to output a viable image if it can make one, notwithstanding
errors. And in this case:
$ ./a.out
Hello, fmt!
[2025-05-07 10:51:57.987] [info] Hello, spdlog!
The .text
section of pthread_create.o
is garbage-collected; the linkage errors,
but the program is perfectly fine.
So we'd expect a clean linkage if we yank .note.stapsdt
out of pthread_create.o
and interpose the modified object file in the link, and so we do:
$ objcopy --remove-section='.note.stapsdt' pthread_create.o pthread_create_nostap.o
$ g++ test.o pthread_create_nostap.o -fuse-ld=gold -static -Wl,-gc-sections
$ ./a.out
Hello, fmt!
[2025-05-07 11:08:27.647] [info] Hello, spdlog!
The program is fine without the .note.stapsdt
and/or the .text
section of
pthread_create.o
, but Systemtap would not be fine with the program. That's
the cash value of the linkage failure.
The linkage error has nothing to do with your particular program.
Check out this deranged linkage:
$ cat main.c
int main(void)
{
return 0;
}
$ gcc main.c -static -Wl,-gc-sections,--whole-archive,-lc,--no-whole-archive
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(dso_handle.o):(.data.rel.ro.local+0x0): multiple definition of `__dso_handle'; /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginT.o:(.data+0x0): first defined here
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(rcmd.o): in function `__validuser2_sa':
(.text+0x5e8): warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(rcmd.o): note: the message above does not take linker garbage collection into account
/usr/bin/ld: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(dl-reloc-static-pie.o): in function `_dl_relocate_static_pie':
(.text+0x0): multiple definition of `_dl_relocate_static_pie'; /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crt1.o:(.text+0x30): first defined here
collect2: error: ld returned 1 exit status
where I'm trying and failing to make a garbage-collected static linkage of the whole of GLIBC into a do-nothing program, with the default linker.
Now let's repeat the failure with gold
:
$ gcc main.c -fuse-ld=gold -static -Wl,-gc-sections,--whole-archive,-lc,--no-whole-archive
/usr/bin/ld.gold: error: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(dso_handle.o): multiple definition of '__dso_handle'
/usr/bin/ld.gold: /usr/lib/gcc/x86_64-linux-gnu/13/crtbeginT.o: previous definition here
/usr/bin/ld.gold: error: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(dl-reloc-static-pie.o): multiple definition of '_dl_relocate_static_pie'
/usr/bin/ld.gold: /usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/crt1.o: previous definition here
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_cond_destroy.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_cond_init.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_create.o)(.note.stapsdt+0x74): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_join_common.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_join_common.o)(.note.stapsdt+0x5c): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_mutex_destroy.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_mutex_init.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_mutex_timedlock.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_mutex_timedlock.o)(.note.stapsdt+0x68): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_mutex_timedlock.o)(.note.stapsdt+0xbc): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_mutex_timedlock.o)(.note.stapsdt+0x11c): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(pthread_rwlock_destroy.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(____longjmp_chk.o)(.note.stapsdt+0x14): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
/usr/lib/gcc/x86_64-linux-gnu/13/../../../x86_64-linux-gnu/libc.a(____longjmp_chk.o)(.note.stapsdt+0x64): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
collect2: error: ld returned 1 exit status
Now we're sprayed with:
libc.a(???.o)(.note.stapsdt+???): error: relocation refers to local symbol ".text" [1], which is defined in a discarded section
errors that weren't there before, the great majority of the ???.o
being pthread_???.o
.
How does gold
come to disregard the note.stapsdt
references into .text
in pthread_create.o
?
To understand that I had to get the binutils-gdb
source code,
study the gold
source and debug a build of it on the problem linkage with ad-hoc diagnostics added. Here is the gist.
gold
's GC algorithm initally reserves a set of GC-root sections in the pre-GC linkage to be retained
unconditionally. These include the section that contains the _start
symbol (or
other non-default program entry symbol), plus all sections that match a hard-coded
set of prefixes or names, including all .note.*
sections. So pthread_create.o(.note.stapsdt)
is one of them.
For each section src_object.o(.src_sec)
of each object file linked - provided it is
a type-ALLOC
section - GC maps that section to list of the relocations ( = references) from src_object.o(.src_sec)
into any other input section dest_object.o(.dest_sec)
, so that if src_object.o(.src_sec)
is
retained then dest_object.o(.dest_sec)
will also be retained. An ALLOC
section here
means one that will occupy space in the process image, as indicated by
by flag SHF_ALLOC
set in the section header. This property can be taken to mean that the section
would be worth garbage collecting. The algorithm
discovers the relocations by reading the corresponding relocations section src_object.o(.rel[a].src_sec
).
Then, starting with the GC-root sections, the algorithm recursively determines for each retained section what other sections it refers to, as per its associated relocations, and adds the sections referred to to the retained list. Finally, all sections not retained are discarded.
This is all as should be, except for the winnowing out of sections that are
not type ALLOC
from relocations gathering. That is a flaw, because a .note.*
section, depending
on its kind, might be type ALLOC
(e.g. .note.gnu.property
, .note.ABI-tag
in this linkage) or it might not
(e.g. .note.gnu.gold-version
, note.stapsdt
in this linkage), and being non-ALLOC
does not
preclude it having relocations into ALLOC
sections. The bug will sleep soundly
as long as a non-ALLOC
.note.*
section that is winnowed out of
GC relocations processing does not contain relocations.
Section pthread_create.o(.note.stapsdt)
is non-ALLOC
:
$ readelf -SW pthread_create.o | egrep '(.note.stapsdt|Section|Flg)'
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ 8] .note.stapsdt NOTE 0000000000000000 001928 0000c8 00 0 0 4
[ 9] .rela.note.stapsdt RELA 0000000000000000 0046f8 000060 18 I 20 8 8
(Flg
A
not set), but does have relocations. So the
bug bites. The GC algorithm never sees the associated
relocations in rela.note.stapsdt
that refer to pthread_create.o(.text)
. When it finds that
pthread_create.o(.note.stapsdt)
is non-ALLOC
it just skips over .pthread_create.o(.rela.note.stapsdt)
without further ado.
Thus GC never records that pthread_create.o(.note.stapsdt)
- retained -
refers to pthread_create.o(.text)
, and since nothing else refers to pthread_create.o(.text)
,
it is discarded. When time comes to apply relocations to pthread_create.o(.note.stapsdt)
,
the section they refer to is no longer in the linkage.
A comment in file binutils-gdb/gold/reloc.cc
explaining the flawed
winnowing test:
// We are scanning relocations in order to fill out the GOT and
// PLT sections. Relocations for sections which are not
// allocated (typically debugging sections) should not add new
// GOT and PLT entries. So we skip them unless this is a
// relocatable link or we need to emit relocations. FIXME: What
// should we do if a linker script maps a section with SHF_ALLOC
// clear to a section with SHF_ALLOC set?
illuminates how .note.stapsdt
sections fall through the cracks. It is
unclear to me why this a priori logic should be allowed to prevail over
contrary evidence that a non-ALLOC
.somesec
section does have relocations as
provided by the existence of a .rel[a].somesec
section. If such
non-ALLOC
sections were acknowledged they would need to be
deferred for special "inverted" GC-handling: Instead of taking their retention
to entail the retention of any sections that they transitively refer to,
GC would need to determine what other sections are to be discarded without reference to the non-ALLOC
ones
and then also discard all the non-ALLOC
ones that refer only to already discarded sections.
The open FIXME
is pointed in our context because it foresees the a priori logic
coming unstuck, but not in quite the way that we observe.
Is there a gold
workaround?
That code comment kindles hope that we might dodge the bug if we were either to:-
-r|--relocatable
), static, garbage-collected preliminary
linkage of test.o
, then statically link the resulting object file
into a program, requesting -nostartfiles
to avoid linking the startup code twice.or:-
-q|--emit relocs
, even though we don't want to emit relocations.But gold
will not play with either of these desperate ruses. The first one:
$ g++ -o bigobj.o test.o -fuse-ld=gold -static -Wl,-r,--entry=_start,-gc-sections
/usr/bin/ld.gold: error: cannot mix -r with --gc-sections or --icf
/usr/bin/ld.gold: internal error in do_layout, at ../../gold/object.cc:1939
collect2: error: ld returned 1 exit status
And the second one:
$ g++ test.o -fuse-ld=gold -static -Wl,-q,-gc-sections
/usr/bin/ld.gold: internal error in do_layout, at ../../gold/object.cc:1939
collect2: error: ld returned 1 exit status
Both of them work with ld.bfd
, where they're not needed (They also work with mold
, and
both fail with lld
). AFAICS the only remedies that work for gold
are the ones we've already seen: either link with --noinhibit-exec
,
or else use objcopy
to make santitised copies of the problem object files from
which redundant note.stapsdt
sections are deleted. At a stretch these might be called workarounds,
but hardly gold workarounds. Obviously a reasonable person would give up
on gold
and use one of the other linkers that just works (as indeed you are resigned to do).
Reporting the bug will likely be thankless because gold
is moribund, as @Eljay commented.
Something you are maybe missing (though not relevantly to the linkage failure).
The linkage option -gc-sections
is routinely used in conjunction with the
compiler options -ffunction-sections
and -fdata-sections
. These respectively direct the
compiler to emit each function definition or data object definition in a section by
itself, and that empowers GC to work unhandicapped by facing unreferenced
definitions that it cannot discard because they are located in sections that also contain
referenced definitions.
In code from which template instantiations are altogether absent
or not prevalent, omitting -ffunction-sections
, -fdata-sections
at compilation
will normally render the pay-off of -gc-sections
considerably sub-optimal. If
template instantiations are prevalent the
handicap is mitigated pro rata to their prevalence by the fact that the C++ compiler for
technical reasons places
template instantiations in their own sections anyway. The handicap is further mitigated by
optimisation level, so for a C++ program made almost entirely of template instantiations such
as yours, with -O3
optimisation, -ffunction-sections
, fdata-sections
at compilation
may have little to no benefit on GC. But as a rule they will produce a GC benefit and the
only effect they can have is for the better.