[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.
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 06ba88a..ef1edbc 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -169,6 +169,7 @@
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 61d4247..e85183e 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -602,8 +602,13 @@
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 f0f6121..0dcf347 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -278,7 +278,11 @@
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;
}