summaryrefslogtreecommitdiffstats
path: root/lld
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2020-01-23 11:52:03 -0800
committerHans Wennborg <hans@chromium.org>2020-01-23 23:06:55 +0100
commit26fd69afd9f3c6bb48b8a4e60578ea8ae919593f (patch)
tree8c0b4aadfe7fea125f2adb3bf9a596c4d51234fe /lld
parented63454d984f2262ce332b9b15d49917be3eac98 (diff)
downloadbcm5719-llvm-26fd69afd9f3c6bb48b8a4e60578ea8ae919593f.tar.gz
bcm5719-llvm-26fd69afd9f3c6bb48b8a4e60578ea8ae919593f.zip
[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. (cherry picked from commit 0fbf28f7aae0ceb70071cac56de345e3ff04439c)
Diffstat (limited to 'lld')
-rw-r--r--lld/ELF/Config.h1
-rw-r--r--lld/ELF/Driver.cpp7
-rw-r--r--lld/ELF/Symbols.cpp6
-rw-r--r--lld/test/ELF/weak-undef-no-dynamic-linker.s15
4 files changed, 27 insertions, 2 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 06ba88a83dd..ef1edbcd199 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -169,6 +169,7 @@ struct Configuration {
bool mipsN32Abi = false;
bool mmapOutputFile;
bool nmagic;
+ bool noDynamicLinker = false;
bool noinhibitExec;
bool nostdlib;
bool oFormatBinary;
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 23da749d307..25330832339 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -602,8 +602,13 @@ static DiscardPolicy getDiscard(opt::InputArgList &args) {
static StringRef getDynamicLinker(opt::InputArgList &args) {
auto *arg = args.getLastArg(OPT_dynamic_linker, OPT_no_dynamic_linker);
- if (!arg || arg->getOption().getID() == OPT_no_dynamic_linker)
+ if (!arg)
+ return "";
+ if (arg->getOption().getID() == OPT_no_dynamic_linker) {
+ // --no-dynamic-linker suppresses undefined weak symbols in .dynsym
+ config->noDynamicLinker = true;
return "";
+ }
return arg->getValue();
}
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index f0f6121009a..0dcf34722d3 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -278,7 +278,11 @@ bool Symbol::includeInDynsym() const {
if (computeBinding() == STB_LOCAL)
return false;
if (!isDefined() && !isCommon())
- return true;
+ // This should unconditionally return true, unfortunately glibc -static-pie
+ // expects undefined weak symbols not to exist in .dynsym, e.g.
+ // __pthread_mutex_lock reference in _dl_add_to_namespace_list,
+ // __pthread_initialize_minimal reference in csu/libc-start.c.
+ return !(config->noDynamicLinker && isUndefWeak());
return exportDynamic || inDynamicList;
}
diff --git a/lld/test/ELF/weak-undef-no-dynamic-linker.s b/lld/test/ELF/weak-undef-no-dynamic-linker.s
new file mode 100644
index 00000000000..fa6936e1ef3
--- /dev/null
+++ b/lld/test/ELF/weak-undef-no-dynamic-linker.s
@@ -0,0 +1,15 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld -pie %t.o -o %t
+# RUN: llvm-readobj --dyn-syms %t | FileCheck %s
+# RUN: ld.lld -pie --no-dynamic-linker %t.o -o %t
+# RUN: llvm-readobj --dyn-syms %t | FileCheck --check-prefix=NO %s
+
+## With --no-dynamic-linker, don't emit undefined weak symbols to .dynsym .
+## This will suppress a relocation.
+# CHECK: Name: foo
+# NO-NOT: Name: foo
+
+.weak foo
+cmpq $0, foo@GOTPCREL(%rip)
+callq foo
OpenPOWER on IntegriCloud