[lld] 0fbf28f - [ELF] --no-dynamic-linker: don't emit undefined weak symbols to .dynsym

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 23 12:25:23 PST 2020


Author: Fangrui Song
Date: 2020-01-23T12:25:15-08:00
New Revision: 0fbf28f7aae0ceb70071cac56de345e3ff04439c

URL: https://github.com/llvm/llvm-project/commit/0fbf28f7aae0ceb70071cac56de345e3ff04439c
DIFF: https://github.com/llvm/llvm-project/commit/0fbf28f7aae0ceb70071cac56de345e3ff04439c.diff

LOG: [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.

Added: 
    lld/test/ELF/weak-undef-no-dynamic-linker.s

Modified: 
    lld/ELF/Config.h
    lld/ELF/Driver.cpp
    lld/ELF/Symbols.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 06ba88a83dd4..ef1edbcd1992 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 61d4247fbf53..e85183e14e24 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 f0f6121009a5..0dcf34722d33 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 000000000000..fa6936e1ef39
--- /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 at GOTPCREL(%rip)
+callq foo


        


More information about the llvm-commits mailing list