diff options
-rw-r--r-- | lld/ELF/InputSection.cpp | 13 | ||||
-rw-r--r-- | lld/ELF/InputSection.h | 2 | ||||
-rw-r--r-- | lld/ELF/Target.cpp | 37 | ||||
-rw-r--r-- | lld/ELF/Target.h | 40 | ||||
-rw-r--r-- | lld/test/elf2/Inputs/shared-ppc64.s | 9 | ||||
-rw-r--r-- | lld/test/elf2/ppc64-toc-restore.s | 45 |
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: |