Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -57,7 +57,7 @@ // 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; } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -38,7 +38,8 @@ template typename llvm::object::ELFFile::uintX_t getLocalRelTarget(const ObjectFile &File, - const typename llvm::object::ELFFile::Elf_Rel &Sym); + const typename llvm::object::ELFFile::Elf_Rel &Sym, + uint32_t Type); bool canBePreempted(const SymbolBody *Body, bool NeedsGot); template bool includeInSymtab(const SymbolBody &B); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -126,7 +126,7 @@ if (Body) Addend += getSymVA(cast>(*Body)); else - Addend += getLocalRelTarget(File, RI); + Addend += getLocalRelTarget(File, RI, Type); } P->setSymbolAndType(0, Target->getRelativeReloc(), IsMips64EL); } @@ -424,15 +424,19 @@ template typename ELFFile::uintX_t lld::elf2::getLocalRelTarget(const ObjectFile &File, - const typename ELFFile::Elf_Rel &RI) { + const typename ELFFile::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::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::uintX_t getLocalRelTarget(const ObjectFile &, - const ELFFile::Elf_Rel &); + const ELFFile::Elf_Rel &, uint32_t); template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, - const ELFFile::Elf_Rel &); + const ELFFile::Elf_Rel &, uint32_t); template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, - const ELFFile::Elf_Rel &); + const ELFFile::Elf_Rel &, uint32_t); template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, - const ELFFile::Elf_Rel &); + const ELFFile::Elf_Rel &, uint32_t); template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); Index: ELF/Target.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -58,6 +58,8 @@ unsigned PltEntrySize = 8; }; +uint64_t getPPC64TocBase(); + extern std::unique_ptr Target; TargetInfo *createTarget(); } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -359,7 +359,7 @@ 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. @@ -440,11 +440,6 @@ 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) { @@ -550,6 +545,7 @@ write64be(L, SA - P); break; case R_PPC64_ADDR64: + case R_PPC64_TOC: write64be(L, SA); break; default: Index: test/elf2/ppc64-shared-rel-toc.s =================================================================== --- /dev/null +++ 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 +