diff options
-rw-r--r-- | lld/ELF/Target.cpp | 1 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 34 | ||||
-rw-r--r-- | lld/test/ELF/dynamic-reloc-in-ro.s | 8 |
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. |