Skip to content

Commit 0fbf28f

Browse files
committed
[ELF] --no-dynamic-linker: don't emit undefined weak symbols to .dynsym
I felt really sad to push this commit for my selfish purpose to make glibc -static-pie build with lld. Some code constructs in glibc require R_X86_64_GOTPCREL/R_X86_64_REX_GOTPCRELX referencing undefined weak to be resolved to a GOT entry not relocated by R_X86_64_GLOB_DAT (GNU ld behavior), e.g. csu/libc-start.c if (__pthread_initialize_minimal != NULL) __pthread_initialize_minimal (); elf/dl-object.c void _dl_add_to_namespace_list (struct link_map *new, Lmid_t nsid) { /* We modify the list of loaded objects. */ __rtld_lock_lock_recursive (GL(dl_load_write_lock)); Emitting a GLOB_DAT will make the address equal &__ehdr_start (true value) and cause elf/ldconfig to segfault. glibc really should move away from weak references, which do not have defined semantics. Temporarily special case --no-dynamic-linker.
1 parent e5caa15 commit 0fbf28f

File tree

4 files changed

+27
-2
lines changed

4 files changed

+27
-2
lines changed

lld/ELF/Config.h

+1
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ struct Configuration {
169169
bool mipsN32Abi = false;
170170
bool mmapOutputFile;
171171
bool nmagic;
172+
bool noDynamicLinker = false;
172173
bool noinhibitExec;
173174
bool nostdlib;
174175
bool oFormatBinary;

lld/ELF/Driver.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,13 @@ static DiscardPolicy getDiscard(opt::InputArgList &args) {
602602

603603
static StringRef getDynamicLinker(opt::InputArgList &args) {
604604
auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
605-
if (!arg || arg->getOption().getID() == OPT_no_dynamic_linker)
605+
if (!arg)
606+
return "";
607+
if (arg->getOption().getID() == OPT_no_dynamic_linker) {
608+
// --no-dynamic-linker suppresses undefined weak symbols in .dynsym
609+
config->noDynamicLinker = true;
606610
return "";
611+
}
607612
return arg->getValue();
608613
}
609614

lld/ELF/Symbols.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,11 @@ bool Symbol::includeInDynsym() const {
278278
if (computeBinding() == STB_LOCAL)
279279
return false;
280280
if (!isDefined() && !isCommon())
281-
return true;
281+
// This should unconditionally return true, unfortunately glibc -static-pie
282+
// expects undefined weak symbols not to exist in .dynsym, e.g.
283+
// __pthread_mutex_lock reference in _dl_add_to_namespace_list,
284+
// __pthread_initialize_minimal reference in csu/libc-start.c.
285+
return !(config->noDynamicLinker && isUndefWeak());
282286

283287
return exportDynamic || inDynamicList;
284288
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
3+
# RUN: ld.lld -pie %t.o -o %t
4+
# RUN: llvm-readobj --dyn-syms %t | FileCheck %s
5+
# RUN: ld.lld -pie --no-dynamic-linker %t.o -o %t
6+
# RUN: llvm-readobj --dyn-syms %t | FileCheck --check-prefix=NO %s
7+
8+
## With --no-dynamic-linker, don't emit undefined weak symbols to .dynsym .
9+
## This will suppress a relocation.
10+
# CHECK: Name: foo
11+
# NO-NOT: Name: foo
12+
13+
.weak foo
14+
cmpq $0, foo@GOTPCREL(%rip)
15+
callq foo

0 commit comments

Comments
 (0)