[lld] r268149 - Don't create dynamic relocations to ro segments.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 29 18:15:17 PDT 2016


Author: rafael
Date: Fri Apr 29 20:15:17 2016
New Revision: 268149

URL: http://llvm.org/viewvc/llvm-project?rev=268149&view=rev
Log:
Don't create dynamic relocations to ro segments.

These would just crash at runtime.

If we ever decide to support rw text segments this should make it easier
to implement as there is now a single point where we notice the problem.

I have tested this with a freebsd buildworld. It found a non pic
assembly file being linked into a .so,. With that fixed, buildworld
finished.

Added:
    lld/trunk/test/ELF/copy-errors.s
Modified:
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/Inputs/protected-shared.s
    lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s
    lld/trunk/test/ELF/copy-in-shared.s
    lld/trunk/test/ELF/eh-frame-dyn-rel.s
    lld/trunk/test/ELF/i386-got-and-copy.s
    lld/trunk/test/ELF/undef-with-plt-addr.s
    lld/trunk/test/ELF/x86-64-reloc-32-fpic.s
    lld/trunk/test/ELF/x86-64-reloc-pc32-fpic.s

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Fri Apr 29 20:15:17 2016
@@ -62,7 +62,8 @@ enum RelExpr {
 inline bool refersToGotEntry(RelExpr Expr) {
   return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT ||
          Expr == R_MIPS_GOT_LOCAL || Expr == R_GOT_PAGE_PC ||
-         Expr == R_GOT_PC || Expr == R_GOT_FROM_END;
+         Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD ||
+         Expr == R_TLSGD_PC;
 }
 
 struct Relocation {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Apr 29 20:15:17 2016
@@ -69,6 +69,7 @@ private:
 
   void scanRelocs(InputSection<ELFT> &C);
   void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
+  RelExpr adjustExpr(SymbolBody &S, bool IsWrite, RelExpr Expr, uint32_t Type);
   void createPhdrs();
   void assignAddresses();
   void assignFileOffsets();
@@ -439,64 +440,10 @@ template <class ELFT> static bool isAbso
   return false;
 }
 
-namespace {
-enum PltNeed { Plt_No, Plt_Explicit, Plt_Implicit };
-}
-
 static bool needsPlt(RelExpr Expr) {
   return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT;
 }
 
-static PltNeed needsPlt(RelExpr Expr, uint32_t Type, const SymbolBody &S) {
-  if (S.isGnuIFunc())
-    return Plt_Explicit;
-  if (S.isPreemptible() && needsPlt(Expr))
-    return Plt_Explicit;
-
-  // This handles a non PIC program call to function in a shared library.
-  // In an ideal world, we could just report an error saying the relocation
-  // can overflow at runtime.
-  // In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
-  // libc.so.
-  //
-  // The general idea on how to handle such cases is to create a PLT entry
-  // and use that as the function value.
-  //
-  // For the static linking part, we just return true and everything else
-  // will use the the PLT entry as the address.
-  //
-  // The remaining problem is making sure pointer equality still works. We
-  // need the help of the dynamic linker for that. We let it know that we have
-  // a direct reference to a so symbol by creating an undefined symbol with a
-  // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
-  // the value of the symbol we created. This is true even for got entries, so
-  // pointer equality is maintained. To avoid an infinite loop, the only entry
-  // that points to the real function is a dedicated got entry used by the
-  // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
-  // R_386_JMP_SLOT, etc).
-  if (S.isShared() && !Config->Pic && S.isFunc())
-    if (!refersToGotEntry(Expr))
-      return Plt_Implicit;
-
-  return Plt_No;
-}
-
-static bool needsCopyRel(RelExpr E, const SymbolBody &S) {
-  if (Config->Shared)
-    return false;
-  if (!S.isShared())
-    return false;
-  if (!S.isObject())
-    return false;
-  if (refersToGotEntry(E))
-    return false;
-  if (needsPlt(E))
-    return false;
-  if (E == R_SIZE)
-    return false;
-  return true;
-}
-
 template <class ELFT>
 static bool isRelRelative(RelExpr E, uint32_t Type, const SymbolBody &Body) {
   if (E == R_SIZE)
@@ -515,6 +462,91 @@ static bool isRelRelative(RelExpr E, uin
   return Target->usesOnlyLowPageBits(Type);
 }
 
+static RelExpr toPlt(RelExpr Expr) {
+  if (Expr == R_PPC_OPD)
+    return R_PPC_PLT_OPD;
+  if (Expr == R_PC)
+    return R_PLT_PC;
+  if (Expr == R_ABS)
+    return R_PLT;
+  return Expr;
+}
+
+static RelExpr fromPlt(RelExpr Expr) {
+  // We decided not to use a plt. Optimize a reference to the plt to a
+  // reference to the symbol itself.
+  if (Expr == R_PLT_PC)
+    return R_PC;
+  if (Expr == R_PPC_PLT_OPD)
+    return R_PPC_OPD;
+  if (Expr == R_PLT)
+    return R_ABS;
+  return Expr;
+}
+
+template <class ELFT>
+RelExpr Writer<ELFT>::adjustExpr(SymbolBody &Body, bool IsWrite, RelExpr Expr,
+                                 uint32_t Type) {
+  if (Body.isGnuIFunc())
+    return toPlt(Expr);
+  bool Preemptible = Body.isPreemptible();
+  if (needsPlt(Expr)) {
+    if (Preemptible)
+      return Expr;
+    return fromPlt(Expr);
+  }
+
+  if (!IsWrite && !refersToGotEntry(Expr) && !needsPlt(Expr) && Preemptible) {
+    // This relocation would require the dynamic linker to write a value
+    // to read only memory. We can hack around it if we are producing an
+    // executable and the refered symbol can be preemepted to refer to the
+    // executable.
+    if (Config->Shared) {
+      StringRef S = getELFRelocationTypeName(Config->EMachine, Type);
+      error("relocation " + S + " cannot be used when making a shared "
+                                "object; recompile with -fPIC.");
+      return Expr;
+    }
+    if (Body.getVisibility() != STV_DEFAULT) {
+      error("Cannot preempt symbol");
+      return Expr;
+    }
+    if (Body.isObject()) {
+      // Produce a copy relocation.
+      auto *B = cast<SharedSymbol<ELFT>>(&Body);
+      if (!B->needsCopy())
+        addCopyRelSymbol(B);
+      return Expr;
+    }
+    if (Body.isFunc()) {
+      // This handles a non PIC program call to function in a shared library.In
+      // an ideal world, we could just report an error saying the relocation can
+      // overflow at runtime. In the real world with glibc, crt1.o has a
+      // R_X86_64_PC32 pointing to libc.so.
+      //
+      // The general idea on how to handle such cases is to create a PLT entry
+      // and use that as the function value.
+      //
+      // For the static linking part, we just return a plt expr and everything
+      // else will use the the PLT entry as the address.
+      //
+      // The remaining problem is making sure pointer equality still works. We
+      // need the help of the dynamic linker for that. We let it know that we
+      // have a direct reference to a so symbol by creating an undefined symbol
+      // with a non zero st_value. Seeing that, the dynamic linker resolves the
+      // symbol to the value of the symbol we created. This is true even for got
+      // entries, so pointer equality is maintained. To avoid an infinite loop,
+      // the only entry that points to the real function is a dedicated got
+      // entry used by the plt. That is identified by special relocation types
+      // (R_X86_64_JUMP_SLOT, R_386_JMP_SLOT, etc).
+      Body.NeedsCopyOrPltAddr = true;
+      return toPlt(Expr);
+    }
+    error("Symbol is missing type");
+  }
+  return Expr;
+}
+
 // The reason we have to do this early scan is as follows
 // * To mmap the output file, we need to know the size
 // * For that, we need to know how many dynamic relocs we will have.
@@ -556,6 +588,14 @@ void Writer<ELFT>::scanRelocs(InputSecti
 
     RelExpr Expr = Target->getRelExpr(Type, Body);
 
+    Expr = adjustExpr(Body, IsWrite, Expr, Type);
+    if (HasError)
+      continue;
+    bool Preemptible = Body.isPreemptible();
+    if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body))
+      if (B->needsCopy())
+        Preemptible = false;
+
     // This relocation does not require got entry, but it is relative to got and
     // needs it to be created. Here we request for that.
     if (Expr == R_GOTONLY_PC || Expr == R_GOTREL || Expr == R_PPC_TOC)
@@ -587,34 +627,10 @@ void Writer<ELFT>::scanRelocs(InputSecti
       AddDyn({Target->RelativeRel, C.OutSec, Offset, true, &Body,
               getAddend<ELFT>(RI)});
 
-    // If a symbol in a DSO is referenced directly instead of through GOT
-    // in a read-only section, we need to create a copy relocation for the
-    // symbol.
-    if (auto *B = dyn_cast<SharedSymbol<ELFT>>(&Body)) {
-      if (!IsWrite && needsCopyRel(Expr, *B)) {
-        if (!B->needsCopy())
-          addCopyRelSymbol(B);
-        C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
-        continue;
-      }
-    }
-
-    bool Preemptible = Body.isPreemptible();
-
     // If a relocation needs PLT, we create a PLT and a GOT slot
     // for the symbol.
-    PltNeed NeedPlt = needsPlt(Expr, Type, Body);
-    if (NeedPlt) {
-      if (NeedPlt == Plt_Implicit)
-        Body.NeedsCopyOrPltAddr = true;
-      RelExpr E = Expr;
-      if (Expr == R_PPC_OPD)
-        E = R_PPC_PLT_OPD;
-      else if (Expr == R_PC)
-        E = R_PLT_PC;
-      else if (Expr == R_ABS)
-        E = R_PLT;
-      C.Relocations.push_back({E, Type, Offset, Addend, &Body});
+    if (needsPlt(Expr)) {
+      C.Relocations.push_back({Expr, Type, Offset, Addend, &Body});
 
       if (Body.isInPlt())
         continue;
@@ -641,15 +657,6 @@ void Writer<ELFT>::scanRelocs(InputSecti
       continue;
     }
 
-    // We decided not to use a plt. Optimize a reference to the plt to a
-    // reference to the symbol itself.
-    if (Expr == R_PLT_PC)
-      Expr = R_PC;
-    if (Expr == R_PPC_PLT_OPD)
-      Expr = R_PPC_OPD;
-    if (Expr == R_PLT)
-      Expr = R_ABS;
-
     if (Target->needsThunk(Type, File, Body)) {
       C.Relocations.push_back({R_THUNK, Type, Offset, Addend, &Body});
       continue;

Modified: lld/trunk/test/ELF/Inputs/protected-shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/protected-shared.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/Inputs/protected-shared.s (original)
+++ lld/trunk/test/ELF/Inputs/protected-shared.s Fri Apr 29 20:15:17 2016
@@ -5,3 +5,6 @@ foo:
         .global bar
         .protected bar
 bar:
+
+        .global zed
+zed:

Modified: lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s (original)
+++ lld/trunk/test/ELF/Inputs/undef-with-plt-addr.s Fri Apr 29 20:15:17 2016
@@ -1,3 +1,7 @@
 	.globl	set_data
 	.type	set_data, at function
 set_data:
+
+        .globl  foo
+        .type   foo, at function
+foo:

Added: lld/trunk/test/ELF/copy-errors.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/copy-errors.s?rev=268149&view=auto
==============================================================================
--- lld/trunk/test/ELF/copy-errors.s (added)
+++ lld/trunk/test/ELF/copy-errors.s Fri Apr 29 20:15:17 2016
@@ -0,0 +1,15 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/protected-shared.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s
+
+.global _start
+_start:
+
+
+call bar
+// CHECK: Cannot preempt symbol
+
+call zed
+// CHECK: Symbol is missing type

Modified: lld/trunk/test/ELF/copy-in-shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/copy-in-shared.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/copy-in-shared.s (original)
+++ lld/trunk/test/ELF/copy-in-shared.s Fri Apr 29 20:15:17 2016
@@ -1,14 +1,10 @@
+// REQUIRES: x86
 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-in-shared.s -o %t1.o
 // RUN: ld.lld -shared %t1.o -o %t1.so
 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
-// RUN: ld.lld %t2.o %t1.so -o %t2.so -shared
-// RUN: llvm-readobj -r %t2.so | FileCheck %s
-// REQUIRES: x86
+// RUN: not ld.lld %t2.o %t1.so -o %t2.so -shared 2>&1 | FileCheck %s
+
 
 .quad foo
 
-// CHECK:      Relocations [
-// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
-// CHECK-NEXT:     R_X86_64_64 foo 0x0
-// CHECK-NEXT:   }
-// CHECK-NEXT: ]
+// CHECK: relocation R_X86_64_64 cannot be used when making a shared object; recompile with -fPIC.

Modified: lld/trunk/test/ELF/eh-frame-dyn-rel.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/eh-frame-dyn-rel.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/eh-frame-dyn-rel.s (original)
+++ lld/trunk/test/ELF/eh-frame-dyn-rel.s Fri Apr 29 20:15:17 2016
@@ -1,13 +1,10 @@
 // REQUIRES: x86
 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
-// RUN: ld.lld %t.o %t.o -o %t -shared
-// RUN: llvm-readobj -r %t | FileCheck %s
+// RUN: not ld.lld %t.o %t.o -o %t -shared 2>&1 | FileCheck %s
 
         .section        bar,"axG", at progbits,foo,comdat
         .cfi_startproc
         .cfi_personality 0x8c, foo
         .cfi_endproc
 
-// CHECK:      Section ({{.*}}) .rela.dyn {
-// CHECK-NEXT:   0x1DA R_X86_64_64 foo 0x0
-// CHECK-NEXT: }
+// CHECK: relocation R_X86_64_64 cannot be used when making a shared object; recompile with -fPIC.

Modified: lld/trunk/test/ELF/i386-got-and-copy.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/i386-got-and-copy.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/i386-got-and-copy.s (original)
+++ lld/trunk/test/ELF/i386-got-and-copy.s Fri Apr 29 20:15:17 2016
@@ -15,7 +15,6 @@
 # CHECK:      Relocations [
 # CHECK-NEXT:   Section (4) .rel.dyn {
 # CHECK-NEXT:     0x{{[0-9A-F]+}} R_386_COPY foo
-# CHECK-NEXT:     0x{{[0-9A-F]+}} R_386_GLOB_DAT foo
 # CHECK-NEXT:   }
 # CHECK-NEXT: ]
 

Modified: lld/trunk/test/ELF/undef-with-plt-addr.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/undef-with-plt-addr.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/undef-with-plt-addr.s (original)
+++ lld/trunk/test/ELF/undef-with-plt-addr.s Fri Apr 29 20:15:17 2016
@@ -3,13 +3,15 @@
 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
 // RUN: ld.lld %t2.o -o %t2.so -shared
 // RUN: ld.lld %t.o %t2.so -o %t3
-// RUN: llvm-readobj -t -s %t3 | FileCheck %s
+// RUN: llvm-readobj -t -s -r %t3 | FileCheck %s
 
 .globl _start
 _start:
 movabsq	$set_data, %rax
 
-// Test that set_data has an address in the .plt
+.data
+.quad foo
+// Test that set_data has an address in the .plt, but foo is not
 
 // CHECK:      Name: .plt
 // CHECK-NEXT: Type: SHT_PROGBITS
@@ -19,5 +21,25 @@ movabsq	$set_data, %rax
 // CHECK-NEXT: ]
 // CHECK-NEXT: Address: 0x11010
 
+// CHECK:      Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:   0x13000 R_X86_64_64 foo 0x0
+// CHECK-NEXT: }
+// CHECK-NEXT: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT:   0x13020 R_X86_64_JUMP_SLOT set_data 0x0
+// CHECK-NEXT: }
+
+// CHECK:      Name: foo
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
 // CHECK:      Name:    set_data
 // CHECK-NEXT: Value:   0x11020
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Function
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined

Modified: lld/trunk/test/ELF/x86-64-reloc-32-fpic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-reloc-32-fpic.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/x86-64-reloc-32-fpic.s (original)
+++ lld/trunk/test/ELF/x86-64-reloc-32-fpic.s Fri Apr 29 20:15:17 2016
@@ -1,6 +1,6 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
 # RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
-# CHECK: R_X86_64_32 cannot be a dynamic relocation
+# CHECK: relocation R_X86_64_32 cannot be used when making a shared object; recompile with -fPIC.
 
 .long _shared

Modified: lld/trunk/test/ELF/x86-64-reloc-pc32-fpic.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/x86-64-reloc-pc32-fpic.s?rev=268149&r1=268148&r2=268149&view=diff
==============================================================================
--- lld/trunk/test/ELF/x86-64-reloc-pc32-fpic.s (original)
+++ lld/trunk/test/ELF/x86-64-reloc-pc32-fpic.s Fri Apr 29 20:15:17 2016
@@ -1,6 +1,6 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
 # RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s
-# CHECK: R_X86_64_PC32 cannot be a dynamic relocation
+# CHECK: relocation R_X86_64_PC32 cannot be used when making a shared object; recompile with -fPIC.
 
 call _shared




More information about the llvm-commits mailing list