summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.h3
-rw-r--r--lld/ELF/Writer.cpp185
-rw-r--r--lld/test/ELF/Inputs/protected-shared.s3
-rw-r--r--lld/test/ELF/Inputs/undef-with-plt-addr.s4
-rw-r--r--lld/test/ELF/copy-errors.s15
-rw-r--r--lld/test/ELF/copy-in-shared.s12
-rw-r--r--lld/test/ELF/eh-frame-dyn-rel.s7
-rw-r--r--lld/test/ELF/i386-got-and-copy.s1
-rw-r--r--lld/test/ELF/undef-with-plt-addr.s26
-rw-r--r--lld/test/ELF/x86-64-reloc-32-fpic.s2
-rw-r--r--lld/test/ELF/x86-64-reloc-pc32-fpic.s2
11 files changed, 152 insertions, 108 deletions
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 21e536f2f6a..4fef6085767 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -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 {
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 86915f31beb..ca668ebe349 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -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 isAbsolute(const SymbolBody &Body) {
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, uint32_t Type, const SymbolBody &Body) {
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(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
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(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
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(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
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;
diff --git a/lld/test/ELF/Inputs/protected-shared.s b/lld/test/ELF/Inputs/protected-shared.s
index 342c37950a8..5f4b1daf63c 100644
--- a/lld/test/ELF/Inputs/protected-shared.s
+++ b/lld/test/ELF/Inputs/protected-shared.s
@@ -5,3 +5,6 @@ foo:
.global bar
.protected bar
bar:
+
+ .global zed
+zed:
diff --git a/lld/test/ELF/Inputs/undef-with-plt-addr.s b/lld/test/ELF/Inputs/undef-with-plt-addr.s
index 4b3a5d3352d..b12737d9e09 100644
--- a/lld/test/ELF/Inputs/undef-with-plt-addr.s
+++ b/lld/test/ELF/Inputs/undef-with-plt-addr.s
@@ -1,3 +1,7 @@
.globl set_data
.type set_data,@function
set_data:
+
+ .globl foo
+ .type foo,@function
+foo:
diff --git a/lld/test/ELF/copy-errors.s b/lld/test/ELF/copy-errors.s
new file mode 100644
index 00000000000..bc28e328ce6
--- /dev/null
+++ b/lld/test/ELF/copy-errors.s
@@ -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
diff --git a/lld/test/ELF/copy-in-shared.s b/lld/test/ELF/copy-in-shared.s
index 1e670138687..273fffa5090 100644
--- a/lld/test/ELF/copy-in-shared.s
+++ b/lld/test/ELF/copy-in-shared.s
@@ -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.
diff --git a/lld/test/ELF/eh-frame-dyn-rel.s b/lld/test/ELF/eh-frame-dyn-rel.s
index 47827a7143a..612e5fd0c20 100644
--- a/lld/test/ELF/eh-frame-dyn-rel.s
+++ b/lld/test/ELF/eh-frame-dyn-rel.s
@@ -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",@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.
diff --git a/lld/test/ELF/i386-got-and-copy.s b/lld/test/ELF/i386-got-and-copy.s
index 3d812d9fbd6..f5b0b8ec5bb 100644
--- a/lld/test/ELF/i386-got-and-copy.s
+++ b/lld/test/ELF/i386-got-and-copy.s
@@ -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: ]
diff --git a/lld/test/ELF/undef-with-plt-addr.s b/lld/test/ELF/undef-with-plt-addr.s
index 89a85dfa684..792d85f3da6 100644
--- a/lld/test/ELF/undef-with-plt-addr.s
+++ b/lld/test/ELF/undef-with-plt-addr.s
@@ -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
diff --git a/lld/test/ELF/x86-64-reloc-32-fpic.s b/lld/test/ELF/x86-64-reloc-32-fpic.s
index d46c5531fa8..b47c0a36c5f 100644
--- a/lld/test/ELF/x86-64-reloc-32-fpic.s
+++ b/lld/test/ELF/x86-64-reloc-32-fpic.s
@@ -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
diff --git a/lld/test/ELF/x86-64-reloc-pc32-fpic.s b/lld/test/ELF/x86-64-reloc-pc32-fpic.s
index 6723177f729..83bf6659098 100644
--- a/lld/test/ELF/x86-64-reloc-pc32-fpic.s
+++ b/lld/test/ELF/x86-64-reloc-pc32-fpic.s
@@ -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
OpenPOWER on IntegriCloud