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,7 +424,8 @@ 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) { typedef typename ELFFile::Elf_Sym Elf_Sym; const Elf_Sym *Sym = File.getObj().getRelocationSymbol(&RI, File.getSymbolTable()); @@ -432,7 +433,7 @@ // For certain special relocations, such as R_PPC64_TOC, there's no // corresponding symbol. Just return 0 in that case. if (!Sym) - return 0; + return Target->getSymbollessRelocVA(Type); // 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 +744,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 @@ -34,6 +34,7 @@ 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 uint64_t getSymbollessRelocVA(uint32_t Type) const; virtual void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, uint32_t Type, uint64_t BaseAddr, uint64_t SymVA) const = 0; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -78,6 +78,7 @@ 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; + uint64_t getSymbollessRelocVA(uint32_t Type) const override; void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, uint32_t Type, uint64_t BaseAddr, uint64_t SA) const override; @@ -154,6 +155,8 @@ bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } +uint64_t TargetInfo::getSymbollessRelocVA(uint32_t Type) const { return 0; } + X86TargetInfo::X86TargetInfo() { PCRelReloc = R_386_PC32; GotReloc = R_386_GLOB_DAT; @@ -430,6 +433,13 @@ } } +uint64_t PPC64TargetInfo::getSymbollessRelocVA(uint32_t Type) const { + if (Type == R_PPC64_TOC) + return getPPC64TocBase(); + + return 0; +} + void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP, uint32_t Type, uint64_t BaseAddr, uint64_t SA) const { @@ -440,11 +450,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 +555,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 +