forked from OSchip/llvm-project
[ELF2] getLocalRelTarget should handle R_PPC64_TOC directly
R_PPC64_TOC does not have an associated symbol, but does have a non-zero VA that target-specific code must compute using some non-trivial rule. We handled this as a special case in PPC64TargetInfo::relocateOne, where we knew to write this special address, but that did not work when creating shared libraries. The special TOC address needs to be the subject of a R_PPC64_RELATIVE relocation, and so we also need to know how to encode this special address in the addend of that relocation. Thus, some target-specific logic is necessary when creating R_PPC64_RELATIVE as well. To solve this problem, we teach getLocalRelTarget to handle R_PPC64_TOC as a special case. This allows us to remove the special case in PPC64TargetInfo::relocateOne (simplifying code there), and naturally allows the existing logic to do the right thing when creating associated R_PPC64_RELATIVE relocations for shared libraries. llvm-svn: 250555
This commit is contained in:
parent
3d5b48c480
commit
6f97c2bc00
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 &);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -58,6 +58,8 @@ protected:
|
|||
unsigned PltEntrySize = 8;
|
||||
};
|
||||
|
||||
uint64_t getPPC64TocBase();
|
||||
|
||||
extern std::unique_ptr<TargetInfo> Target;
|
||||
TargetInfo *createTarget();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
Loading…
Reference in New Issue