Skip to content

Commit

Permalink
[ELF] --no-dynamic-linker: don't emit undefined weak symbols to .dynsym
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
MaskRay committed Jan 23, 2020
1 parent e5caa15 commit 0fbf28f
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 2 deletions.
1 change: 1 addition & 0 deletions lld/ELF/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ struct Configuration {
bool mipsN32Abi = false;
bool mmapOutputFile;
bool nmagic;
bool noDynamicLinker = false;
bool noinhibitExec;
bool nostdlib;
bool oFormatBinary;
Expand Down
7 changes: 6 additions & 1 deletion lld/ELF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down
6 changes: 5 additions & 1 deletion lld/ELF/Symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
15 changes: 15 additions & 0 deletions lld/test/ELF/weak-undef-no-dynamic-linker.s
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 0fbf28f

Please sign in to comment.