summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/Target.cpp1
-rw-r--r--lld/ELF/Writer.cpp34
-rw-r--r--lld/test/ELF/dynamic-reloc-in-ro.s8
3 files changed, 30 insertions, 13 deletions
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index df41fcde999..72544103db6 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -976,6 +976,7 @@ bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const {
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LDST128_ABS_LO12_NC:
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
return true;
}
}
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 4b8849fb6fc..63ed12a64e1 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -442,14 +442,25 @@ static bool needsPlt(RelExpr Expr) {
template <class ELFT>
static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type,
const SymbolBody &Body) {
- if (E == R_SIZE)
+ // These expressions always compute a constant
+ if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || E == R_MIPS_GOT ||
+ E == R_MIPS_GOT_LOCAL || E == R_GOT_PAGE_PC || E == R_GOT_PC ||
+ E == R_PLT_PC || E == R_TLSGD_PC || E == R_TLSGD || E == R_PPC_PLT_OPD)
return true;
- bool AbsVal = (isAbsolute<ELFT>(Body) || Body.isTls()) &&
- !refersToGotEntry(E) && !needsPlt(E);
+ // These never do, except if the entire file is position dependent or if
+ // only the low bits are used.
+ if (E == R_GOT || E == R_PLT)
+ return Target->usesOnlyLowPageBits(Type) || !Config->Pic;
- bool RelE = E == R_PC || E == R_PLT_PC || E == R_GOT_PC || E == R_GOTREL ||
- E == R_PAGE_PC;
+ if (Body.isPreemptible())
+ return false;
+
+ if (!Config->Pic)
+ return true;
+
+ bool AbsVal = isAbsolute<ELFT>(Body) || Body.isTls();
+ bool RelE = E == R_PC || E == R_GOTREL || E == R_PAGE_PC;
if (AbsVal && !RelE)
return true;
if (!AbsVal && RelE)
@@ -497,16 +508,13 @@ static RelExpr fromPlt(RelExpr 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 (Body.isGnuIFunc())
+ Expr = toPlt(Expr);
+ else if (needsPlt(Expr) && !Preemptible)
+ Expr = fromPlt(Expr);
- if (IsWrite || refersToGotEntry(Expr) || needsPlt(Expr) || !Preemptible)
+ if (IsWrite || isStaticLinkTimeConstant<ELFT>(Expr, Type, Body))
return Expr;
// This relocation would require the dynamic linker to write a value to read
diff --git a/lld/test/ELF/dynamic-reloc-in-ro.s b/lld/test/ELF/dynamic-reloc-in-ro.s
new file mode 100644
index 00000000000..00a83b6ad65
--- /dev/null
+++ b/lld/test/ELF/dynamic-reloc-in-ro.s
@@ -0,0 +1,8 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s
+
+foo:
+.quad foo
+
+// CHECK: relocation R_X86_64_64 cannot be used when making a shared object; recompile with -fPIC.
OpenPOWER on IntegriCloud