diff options
| -rw-r--r-- | lld/ELF/InputSection.cpp | 2 | ||||
| -rw-r--r-- | lld/ELF/OutputSections.cpp | 22 | ||||
| -rw-r--r-- | lld/ELF/OutputSections.h | 3 | ||||
| -rw-r--r-- | lld/ELF/Target.cpp | 8 | ||||
| -rw-r--r-- | lld/ELF/Target.h | 2 | ||||
| -rw-r--r-- | lld/test/elf2/ppc64-shared-rel-toc.s | 27 |
6 files changed, 47 insertions, 17 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 8a0a5898e03..90823a8e755 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -57,7 +57,7 @@ void InputSection<ELFT>::relocate( // resolved so we don't allocate a SymbolBody. const Elf_Shdr *SymTab = File.getSymbolTable(); if (SymIndex < SymTab->sh_info) { - uintX_t SymVA = getLocalRelTarget(File, RI); + uintX_t SymVA = getLocalRelTarget(File, RI, Type); relocateOne(Buf, BufEnd, RI, Type, BaseAddr, SymVA); continue; } diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 7f7b970a72f..a8545c301ed 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -126,7 +126,7 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { if (Body) Addend += getSymVA<ELFT>(cast<ELFSymbolBody<ELFT>>(*Body)); else - Addend += getLocalRelTarget(File, RI); + Addend += getLocalRelTarget(File, RI, Type); } P->setSymbolAndType(0, Target->getRelativeReloc(), IsMips64EL); } @@ -424,15 +424,19 @@ typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) { template <class ELFT> typename ELFFile<ELFT>::uintX_t lld::elf2::getLocalRelTarget(const ObjectFile<ELFT> &File, - const typename ELFFile<ELFT>::Elf_Rel &RI) { + const typename ELFFile<ELFT>::Elf_Rel &RI, + uint32_t Type) { + // PPC64 has a special relocation representing the TOC base pointer + // that does not have a corresponding symbol. + if (Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC) + return getPPC64TocBase(); + typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym; const Elf_Sym *Sym = File.getObj().getRelocationSymbol(&RI, File.getSymbolTable()); - // For certain special relocations, such as R_PPC64_TOC, there's no - // corresponding symbol. Just return 0 in that case. if (!Sym) - return 0; + error("Unsupported relocation without symbol"); // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule @@ -743,19 +747,19 @@ template ELFFile<ELF64BE>::uintX_t getSymVA<ELF64BE>(const SymbolBody &); template ELFFile<ELF32LE>::uintX_t getLocalRelTarget(const ObjectFile<ELF32LE> &, - const ELFFile<ELF32LE>::Elf_Rel &); + const ELFFile<ELF32LE>::Elf_Rel &, uint32_t); template ELFFile<ELF32BE>::uintX_t getLocalRelTarget(const ObjectFile<ELF32BE> &, - const ELFFile<ELF32BE>::Elf_Rel &); + const ELFFile<ELF32BE>::Elf_Rel &, uint32_t); template ELFFile<ELF64LE>::uintX_t getLocalRelTarget(const ObjectFile<ELF64LE> &, - const ELFFile<ELF64LE>::Elf_Rel &); + const ELFFile<ELF64LE>::Elf_Rel &, uint32_t); template ELFFile<ELF64BE>::uintX_t getLocalRelTarget(const ObjectFile<ELF64BE> &, - const ELFFile<ELF64BE>::Elf_Rel &); + const ELFFile<ELF64BE>::Elf_Rel &, uint32_t); template bool includeInSymtab<ELF32LE>(const SymbolBody &); template bool includeInSymtab<ELF32BE>(const SymbolBody &); diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 0892ce81834..4c62f70d863 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -38,7 +38,8 @@ typename llvm::object::ELFFile<ELFT>::uintX_t getSymVA(const SymbolBody &S); template <class ELFT> typename llvm::object::ELFFile<ELFT>::uintX_t getLocalRelTarget(const ObjectFile<ELFT> &File, - const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Sym); + const typename llvm::object::ELFFile<ELFT>::Elf_Rel &Sym, + uint32_t Type); bool canBePreempted(const SymbolBody *Body, bool NeedsGot); template <class ELFT> bool includeInSymtab(const SymbolBody &B); diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 4ecc80b592c..f45b6c54c2c 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -345,7 +345,7 @@ PPC64TargetInfo::PPC64TargetInfo() { VAStart = 0x10000000; } -static uint64_t getPPC64TocBase() { +uint64_t getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that // order. The TOC starts where the first of these sections starts. @@ -426,11 +426,6 @@ void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, uint64_t P = BaseAddr + Rel.r_offset; uint64_t TB = getPPC64TocBase(); - if (Type == R_PPC64_TOC) { - write64be(L, TB); - return; - } - // For a TOC-relative relocation, adjust the addend and proceed in terms of // the corresponding ADDR16 relocation type. switch (Type) { @@ -536,6 +531,7 @@ void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, write64be(L, SA - P); break; case R_PPC64_ADDR64: + case R_PPC64_TOC: write64be(L, SA); break; default: diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index ff770e1a477..1faaf02931d 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -58,6 +58,8 @@ protected: unsigned PltEntrySize = 8; }; +uint64_t getPPC64TocBase(); + extern std::unique_ptr<TargetInfo> Target; TargetInfo *createTarget(); } diff --git a/lld/test/elf2/ppc64-shared-rel-toc.s b/lld/test/elf2/ppc64-shared-rel-toc.s new file mode 100644 index 00000000000..2b3ad51afa0 --- /dev/null +++ b/lld/test/elf2/ppc64-shared-rel-toc.s @@ -0,0 +1,27 @@ +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: ld.lld2 -shared %t.o -o %t.so +// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s +// REQUIRES: ppc + +// When we create the TOC reference in the shared library, make sure that the +// R_PPC64_RELATIVE relocation uses the correct (non-zero) offset. + + .globl foo + .align 2 + .type foo,@function + .section .opd,"aw",@progbits +foo: # @foo + .align 3 + .quad .Lfunc_begin0 + .quad .TOC.@tocbase + .quad 0 + .text +.Lfunc_begin0: + blr + +// CHECK: 0x20090 R_PPC64_RELATIVE - 0x10000 +// CHECK: 0x20098 R_PPC64_RELATIVE - 0x8000 + +// CHECK: Name: foo (20) +// CHECK-NEXT: Value: 0x20090 + |

