[lld] r250311 - Handle dynamic relocs to weak undefined when possible.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 14 11:42:17 PDT 2015


Author: rafael
Date: Wed Oct 14 13:42:16 2015
New Revision: 250311

URL: http://llvm.org/viewvc/llvm-project?rev=250311&view=rev
Log:
Handle dynamic relocs to weak undefined when possible.

Added:
    lld/trunk/test/elf2/dynamic-reloc-weak.s
Modified:
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=250311&r1=250310&r2=250311&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Wed Oct 14 13:42:16 2015
@@ -52,7 +52,7 @@ template <class ELFT> void GotSection<EL
   for (const SymbolBody *B : Entries) {
     uint8_t *Entry = Buf;
     Buf += sizeof(uintX_t);
-    if (canBePreempted(B))
+    if (canBePreempted(B, false))
       continue; // The dynamic linker will take care of it.
     uintX_t VA = getSymVA<ELFT>(*B);
     write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA);
@@ -122,7 +122,8 @@ template <class ELFT> void RelocationSec
 
     uint32_t Type = RI.getType(IsMips64EL);
 
-    bool CanBePreempted = canBePreempted(Body);
+    bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body);
+    bool CanBePreempted = canBePreempted(Body, NeedsGot);
     uintX_t Addend = 0;
     if (!CanBePreempted) {
       if (IsRela) {
@@ -134,7 +135,7 @@ template <class ELFT> void RelocationSec
       P->setSymbolAndType(0, Target->getRelativeReloc(), IsMips64EL);
     }
 
-    if (Body && Target->relocNeedsGot(Type, *Body)) {
+    if (NeedsGot) {
       P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body);
       if (CanBePreempted)
         P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
@@ -458,13 +459,34 @@ lld::elf2::getLocalRelTarget(const Objec
 
 // Returns true if a symbol can be replaced at load-time by a symbol
 // with the same name defined in other ELF executable or DSO.
-bool lld::elf2::canBePreempted(const SymbolBody *Body) {
+bool lld::elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
   if (!Body)
     return false;  // Body is a local symbol.
   if (Body->isShared())
     return true;
-  if (Body->isUndefined() && !Body->isWeak())
-    return true;
+
+  if (Body->isUndefined()) {
+    if (!Body->isWeak())
+      return true;
+
+    // This is an horrible corner case. Ideally we would like to say that any
+    // undefined symbol can be preempted so that the dynamic linker has a
+    // chance of finding it at runtime.
+    //
+    // The problem is that the code sequence used to test for weak undef
+    // functions looks like
+    // if (func) func()
+    // If the code is -fPIC the first reference is a load from the got and
+    // everything works.
+    // If the code is not -fPIC there is no reasonable way to solve it:
+    // * A relocation writing to the text segment will fail (it is ro).
+    // * A copy relocation doesn't work for functions.
+    // * The trick of using a plt entry as the address would fail here since
+    //   the plt entry would have a non zero address.
+    // Since we cannot do anything better, we just resolve the symbol to 0 and
+    // don't produce a dynamic relocation.
+    return NeedsGot;
+  }
   if (!Config->Shared)
     return false;
   return Body->getMostConstrainingVisibility() == STV_DEFAULT;

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=250311&r1=250310&r2=250311&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Wed Oct 14 13:42:16 2015
@@ -39,7 +39,7 @@ template <class ELFT>
 typename llvm::object::ELFFile<ELFT>::uintX_t
 getLocalRelTarget(const ObjectFile<ELFT> &File,
                   const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Sym);
-bool canBePreempted(const SymbolBody *Body);
+bool canBePreempted(const SymbolBody *Body, bool NeedsGot);
 template <class ELFT> bool includeInSymtab(const SymbolBody &B);
 
 bool includeInDynamicSymtab(const SymbolBody &B);

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=250311&r1=250310&r2=250311&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Oct 14 13:42:16 2015
@@ -191,20 +191,22 @@ void Writer<ELFT>::scanRelocs(
 
     if (Body)
       Body = Body->repl();
+    bool NeedsGot = false;
     if (Body) {
       if (Target->relocNeedsPlt(Type, *Body)) {
         if (Body->isInPlt())
           continue;
         Out<ELFT>::Plt->addEntry(Body);
       }
-      if (Target->relocNeedsGot(Type, *Body)) {
+      NeedsGot = Target->relocNeedsGot(Type, *Body);
+      if (NeedsGot) {
         if (Body->isInGot())
           continue;
         Out<ELFT>::Got->addEntry(Body);
       }
     }
 
-    bool CBP = canBePreempted(Body);
+    bool CBP = canBePreempted(Body, NeedsGot);
     if (!CBP && (!Config->Shared || Target->isRelRelative(Type)))
       continue;
     if (CBP)

Added: lld/trunk/test/elf2/dynamic-reloc-weak.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/dynamic-reloc-weak.s?rev=250311&view=auto
==============================================================================
--- lld/trunk/test/elf2/dynamic-reloc-weak.s (added)
+++ lld/trunk/test/elf2/dynamic-reloc-weak.s Wed Oct 14 13:42:16 2015
@@ -0,0 +1,31 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: ld.lld2 -shared %t2.o -o %t2.so
+// RUN: ld.lld2 %t.o %t2.so -o %t
+// RUN: llvm-readobj -r  %t | FileCheck %s
+// REQUIRES: x86
+
+        .globl _start
+_start:
+        .type sym1, at function
+        .weak sym1
+        .long sym1 at gotpcrel
+
+        .type sym2, at function
+        .weak sym2
+        .long sym2 at plt
+
+        .type sym3, at function
+        .weak sym3
+        .quad sym3
+
+// Both gold and bfd ld will produce a relocation for sym1 and sym2 only. That
+// That seems odd.  If the dynamic linker must get a chance to resolve sym1
+// and sym2, that should also be the case for sym3.
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_GLOB_DAT sym1 0x0
+// CHECK-NEXT:     0x{{.*}} R_X86_64_GLOB_DAT sym2 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]




More information about the llvm-commits mailing list