From 0fbf28f7aae0ceb70071cac56de345e3ff04439c Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Thu, 23 Jan 2020 11:52:03 -0800 Subject: [PATCH] [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. --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 7 ++++++- lld/ELF/Symbols.cpp | 6 +++++- lld/test/ELF/weak-undef-no-dynamic-linker.s | 15 +++++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 lld/test/ELF/weak-undef-no-dynamic-linker.s 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@GOTPCREL(%rip) +callq foo