summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp13
-rw-r--r--lld/ELF/InputSection.h2
-rw-r--r--lld/ELF/Target.cpp37
-rw-r--r--lld/ELF/Target.h40
-rw-r--r--lld/test/elf2/Inputs/shared-ppc64.s9
-rw-r--r--lld/test/elf2/ppc64-toc-restore.s45
6 files changed, 111 insertions, 35 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index fde71270cf4..eabfeb15d68 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -28,7 +28,8 @@ InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
template <class ELFT>
template <bool isRela>
void InputSection<ELFT>::relocate(
- uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
+ uint8_t *Buf, uint8_t *BufEnd,
+ iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
const ObjectFile<ELFT> &File, uintX_t BaseAddr) {
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
bool IsMips64EL = File.getObj().isMips64EL();
@@ -41,8 +42,8 @@ void InputSection<ELFT>::relocate(
const Elf_Shdr *SymTab = File.getSymbolTable();
if (SymIndex < SymTab->sh_info) {
uintX_t SymVA = getLocalRelTarget(File, RI);
- Target->relocateOne(Buf, reinterpret_cast<const void *>(&RI), Type,
- BaseAddr, SymVA);
+ Target->relocateOne(Buf, BufEnd, reinterpret_cast<const void *>(&RI),
+ Type, BaseAddr, SymVA);
continue;
}
@@ -60,7 +61,7 @@ void InputSection<ELFT>::relocate(
} else if (isa<SharedSymbol<ELFT>>(Body)) {
continue;
}
- Target->relocateOne(Buf, reinterpret_cast<const void *>(&RI), Type,
+ Target->relocateOne(Buf, BufEnd, reinterpret_cast<const void *>(&RI), Type,
BaseAddr, SymVA);
}
}
@@ -79,9 +80,9 @@ template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
// Iterate over all relocation sections that apply to this section.
for (const Elf_Shdr *RelSec : RelocSections) {
if (RelSec->sh_type == SHT_RELA)
- relocate(Base, EObj.relas(RelSec), *File, BaseAddr);
+ relocate(Base, Base + Data.size(), EObj.relas(RelSec), *File, BaseAddr);
else
- relocate(Base, EObj.rels(RelSec), *File, BaseAddr);
+ relocate(Base, Base + Data.size(), EObj.rels(RelSec), *File, BaseAddr);
}
}
diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h
index 038c659d144..eea4c2df5e6 100644
--- a/lld/ELF/InputSection.h
+++ b/lld/ELF/InputSection.h
@@ -60,7 +60,7 @@ public:
private:
template <bool isRela>
- void relocate(uint8_t *Buf,
+ void relocate(uint8_t *Buf, uint8_t *BufEnd,
llvm::iterator_range<
const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
const ObjectFile<ELFT> &File, uintX_t BaseAddr);
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 8d3a3515d5a..6f84ada243a 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -64,8 +64,9 @@ bool X86TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); }
static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); }
-void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const {
+void X86TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const {
typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
@@ -164,9 +165,9 @@ bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
}
}
-void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
- uint32_t Type, uint64_t BaseAddr,
- uint64_t SymVA) const {
+void X86_64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+ const void *RelP, uint32_t Type,
+ uint64_t BaseAddr, uint64_t SymVA) const {
typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
@@ -306,7 +307,8 @@ bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
}
}
-void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+ const void *RelP, uint32_t Type,
uint64_t BaseAddr, uint64_t SymVA) const {
typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
@@ -397,6 +399,14 @@ void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
if (!isInt<24>(R - P))
error("Relocation R_PPC64_REL24 overflow");
write32be(L, (read32be(L) & ~Mask) | ((R - P) & Mask));
+
+ uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
+ uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
+ bool InPlt = PltStart <= S + A && S + A < PltEnd;
+
+ if (InPlt && L + 8 < BufEnd &&
+ read32be(L + 4) == 0x60000000 /* nop */)
+ write32be(L + 4, 0xe8410028); // ld %r2, 40(%r1)
break;
}
case R_PPC64_REL32:
@@ -429,7 +439,8 @@ bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
return false;
}
-void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void PPCTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+ const void *RelP, uint32_t Type,
uint64_t BaseAddr, uint64_t SymVA) const {}
ARMTargetInfo::ARMTargetInfo() {
@@ -445,7 +456,8 @@ bool ARMTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
bool ARMTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
return false;
}
-void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void ARMTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+ const void *RelP, uint32_t Type,
uint64_t BaseAddr, uint64_t SymVA) const {}
AArch64TargetInfo::AArch64TargetInfo() {
@@ -478,9 +490,9 @@ static uint64_t getAArch64Page(uint64_t Expr) {
return Expr & (~static_cast<uint64_t>(0xFFF));
}
-void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
- uint32_t Type, uint64_t BaseAddr,
- uint64_t SymVA) const {
+void AArch64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+ const void *RelP, uint32_t Type,
+ uint64_t BaseAddr, uint64_t SymVA) const {
typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
@@ -544,7 +556,8 @@ bool MipsTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
return false;
}
-void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void MipsTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+ const void *RelP, uint32_t Type,
uint64_t BaseAddr, uint64_t SymVA) const {
typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 0eb28a1a9fb..94a343030ac 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -33,8 +33,9 @@ public:
virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0;
virtual bool relocPointsToGot(uint32_t Type) const;
virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0;
- virtual void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const = 0;
+ virtual void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const = 0;
virtual ~TargetInfo();
@@ -56,8 +57,9 @@ public:
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocPointsToGot(uint32_t Type) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
};
class X86_64TargetInfo final : public TargetInfo {
@@ -67,8 +69,9 @@ public:
uint64_t PltEntryAddr) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
bool isRelRelative(uint32_t Type) const override;
};
@@ -79,8 +82,9 @@ public:
uint64_t PltEntryAddr) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
bool isRelRelative(uint32_t Type) const override;
};
@@ -91,8 +95,9 @@ public:
uint64_t PltEntryAddr) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
};
class ARMTargetInfo final : public TargetInfo {
@@ -102,8 +107,9 @@ public:
uint64_t PltEntryAddr) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
};
class AArch64TargetInfo final : public TargetInfo {
@@ -113,8 +119,9 @@ public:
uint64_t PltEntryAddr) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
};
class MipsTargetInfo final : public TargetInfo {
@@ -124,8 +131,9 @@ public:
uint64_t PltEntryAddr) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
- void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
- uint64_t BaseAddr, uint64_t SymVA) const override;
+ void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+ uint32_t Type, uint64_t BaseAddr,
+ uint64_t SymVA) const override;
};
extern std::unique_ptr<TargetInfo> Target;
diff --git a/lld/test/elf2/Inputs/shared-ppc64.s b/lld/test/elf2/Inputs/shared-ppc64.s
new file mode 100644
index 00000000000..b0117ac4296
--- /dev/null
+++ b/lld/test/elf2/Inputs/shared-ppc64.s
@@ -0,0 +1,9 @@
+.section ".opd","aw"
+.global bar
+bar:
+.quad .Lbar,.TOC.@tocbase,0
+.quad .Lbar,0,0
+
+.text
+.Lbar:
+ blr
diff --git a/lld/test/elf2/ppc64-toc-restore.s b/lld/test/elf2/ppc64-toc-restore.s
new file mode 100644
index 00000000000..3aa121bf46a
--- /dev/null
+++ b/lld/test/elf2/ppc64-toc-restore.s
@@ -0,0 +1,45 @@
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
+// RUN: ld.lld2 -shared %t2.o -o %t2.so
+// RUN: ld.lld2 -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// REQUIRES: ppc
+
+// CHECK: Disassembly of section .text:
+
+.global _start
+_start:
+ bl bar
+ nop
+
+// CHECK: _start:
+// CHECK: 10010000: 48 00 00 21 bl .+32
+// CHECK-NOT: 10010004: 60 00 00 00 nop
+// CHECK: 10010004: e8 41 00 28 ld 2, 40(1)
+
+.global noret
+noret:
+ bl bar
+ li 5, 7
+
+// CHECK: noret:
+// CHECK: 10010008: 48 00 00 19 bl .+24
+// CHECK: 1001000c: 38 a0 00 07 li 5, 7
+
+.global noretend
+noretend:
+ bl bar
+
+// CHECK: noretend:
+// CHECK: 10010010: 48 00 00 11 bl .+16
+
+.global noretb
+noretb:
+ b bar
+
+// CHECK: noretb:
+// CHECK: 10010014: 48 00 00 0c b .+12
+
+// CHECK: Disassembly of section .plt:
+// CHECK: .plt:
+// CHECK: 10010020:
OpenPOWER on IntegriCloud