forked from OSchip/llvm-project
[lld] [ELF/AArch64] Fix R_AARCH64_ABS64 in Shared mode
This patch fixes the R_AARCH64_ABS64 relocation when used in shared mode,
where it requires a dynamic R_AARCH64_RELATIVE relocation. To correct set
the addend on the dynamic relocation (since it will be used by the dynamic
linker), a new TargetInfo specific hook was created (getDynRelativeAddend)
to get the correct addend based on relocation type.
The patch fixes the issues when creating shared library code against
{init,fini}_array, where it issues R_AARCH64_ABS64 relocation against
local symbols.
llvm-svn: 261651
This commit is contained in:
parent
a1c6269c91
commit
668ad0ffcb
|
|
@ -253,11 +253,18 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
|||
|
||||
if (IsRela) {
|
||||
uintX_t VA = 0;
|
||||
if (Rel.UseSymVA)
|
||||
if (Rel.UseSymVA) {
|
||||
VA = Sym->getVA<ELFT>();
|
||||
else if (Rel.TargetSec)
|
||||
} else if (Rel.TargetSec) {
|
||||
VA = Rel.TargetSec->getOffset(Rel.OffsetInTargetSec) +
|
||||
Rel.TargetSec->OutSec->getVA();
|
||||
} else if (!Sym && Rel.OffsetSec) {
|
||||
// Sym equal to nullptr means the dynamic relocation is against a
|
||||
// local symbol represented by Rel.SymIndex.
|
||||
ObjectFile<ELFT> *File = Rel.OffsetSec->getFile();
|
||||
const Elf_Sym *LocalSym = File->getLocalSymbol(Rel.SymIndex);
|
||||
VA = getLocalTarget(*File, *LocalSym, 0);
|
||||
}
|
||||
reinterpret_cast<Elf_Rela *>(P)->r_addend = Rel.Addend + VA;
|
||||
}
|
||||
|
||||
|
|
@ -862,7 +869,6 @@ elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
|
|||
const Elf_Rel_Impl<ELFT, IsRela> &RI,
|
||||
typename ELFFile<ELFT>::uintX_t Addend) {
|
||||
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
||||
// PPC64 has a special relocation representing the TOC base pointer
|
||||
// that does not have a corresponding symbol.
|
||||
|
|
@ -875,10 +881,22 @@ elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
|
|||
if (!Sym)
|
||||
fatal("Unsupported relocation without symbol");
|
||||
|
||||
InputSectionBase<ELFT> *Section = File.getSection(*Sym);
|
||||
return getLocalTarget(File, *Sym, Addend);
|
||||
}
|
||||
|
||||
if (Sym->getType() == STT_TLS)
|
||||
return (Section->OutSec->getVA() + Section->getOffset(*Sym) + Addend) -
|
||||
template <class ELFT>
|
||||
typename ELFFile<ELFT>::uintX_t
|
||||
elf2::getLocalTarget(const ObjectFile<ELFT> &File,
|
||||
const typename ELFFile<ELFT>::Elf_Sym &Sym,
|
||||
typename ELFFile<ELFT>::uintX_t Addend) {
|
||||
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
||||
InputSectionBase<ELFT> *Section = File.getSection(Sym);
|
||||
if (!Section)
|
||||
return Addend;
|
||||
|
||||
if (Sym.getType() == STT_TLS)
|
||||
return (Section->OutSec->getVA() + Section->getOffset(Sym) + Addend) -
|
||||
Out<ELFT>::TlsPhdr->p_vaddr;
|
||||
|
||||
// According to the ELF spec reference to a local symbol from outside
|
||||
|
|
@ -888,8 +906,8 @@ elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
|
|||
if (Section == &InputSection<ELFT>::Discarded || !Section->isLive())
|
||||
return Addend;
|
||||
|
||||
uintX_t Offset = Sym->st_value;
|
||||
if (Sym->getType() == STT_SECTION) {
|
||||
uintX_t Offset = Sym.st_value;
|
||||
if (Sym.getType() == STT_SECTION) {
|
||||
Offset += Addend;
|
||||
Addend = 0;
|
||||
}
|
||||
|
|
@ -1647,5 +1665,18 @@ template uint64_t getLocalRelTarget(const ObjectFile<ELF64LE> &,
|
|||
template uint64_t getLocalRelTarget(const ObjectFile<ELF64BE> &,
|
||||
const ELFFile<ELF64BE>::Elf_Rela &,
|
||||
uint64_t);
|
||||
|
||||
template uint32_t getLocalTarget(const ObjectFile<ELF32LE> &,
|
||||
const ELFFile<ELF32LE>::Elf_Sym &Sym,
|
||||
uint32_t);
|
||||
template uint32_t getLocalTarget(const ObjectFile<ELF32BE> &,
|
||||
const ELFFile<ELF32BE>::Elf_Sym &Sym,
|
||||
uint32_t);
|
||||
template uint64_t getLocalTarget(const ObjectFile<ELF64LE> &,
|
||||
const ELFFile<ELF64LE>::Elf_Sym &Sym,
|
||||
uint64_t);
|
||||
template uint64_t getLocalTarget(const ObjectFile<ELF64BE> &,
|
||||
const ELFFile<ELF64BE>::Elf_Sym &Sym,
|
||||
uint64_t);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ getLocalRelTarget(const ObjectFile<ELFT> &File,
|
|||
const llvm::object::Elf_Rel_Impl<ELFT, IsRela> &Rel,
|
||||
typename llvm::object::ELFFile<ELFT>::uintX_t Addend);
|
||||
|
||||
template <class ELFT>
|
||||
typename llvm::object::ELFFile<ELFT>::uintX_t
|
||||
getLocalTarget(const ObjectFile<ELFT> &File,
|
||||
const typename llvm::object::ELFFile<ELFT>::Elf_Sym &Sym,
|
||||
typename llvm::object::ELFFile<ELFT>::uintX_t Addend);
|
||||
|
||||
bool canBePreempted(const SymbolBody *Body, bool NeedsGot);
|
||||
|
||||
// This represents a section in an output file.
|
||||
|
|
@ -187,6 +193,7 @@ template <class ELFT> struct DynamicReloc {
|
|||
} OKind;
|
||||
|
||||
SymbolBody *Sym = nullptr;
|
||||
uint32_t SymIndex = 0;
|
||||
InputSectionBase<ELFT> *OffsetSec = nullptr;
|
||||
uintX_t OffsetInSec = 0;
|
||||
bool UseSymVA = false;
|
||||
|
|
@ -206,6 +213,12 @@ template <class ELFT> struct DynamicReloc {
|
|||
: Type(Type), OKind(Off_Sec), Sym(Sym), OffsetSec(OffsetSec),
|
||||
OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {}
|
||||
|
||||
DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
|
||||
uintX_t OffsetInSec, bool UseSymVA, uint32_t SymIndex,
|
||||
uintX_t Addend)
|
||||
: Type(Type), OKind(Off_Sec), SymIndex(SymIndex), OffsetSec(OffsetSec),
|
||||
OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {}
|
||||
|
||||
DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
|
||||
uintX_t OffsetInSec, InputSectionBase<ELFT> *TargetSec,
|
||||
uintX_t OffsetInTargetSec, uintX_t Addend)
|
||||
|
|
@ -254,6 +267,7 @@ private:
|
|||
|
||||
template <class ELFT>
|
||||
class RelocationSection final : public OutputSectionBase<ELFT> {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ public:
|
|||
unsigned getTlsGotRel(unsigned Type) const override;
|
||||
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
|
||||
bool needsCopyRelImpl(uint32_t Type) const override;
|
||||
bool needsDynRelative(unsigned Type) const override;
|
||||
bool needsGot(uint32_t Type, SymbolBody &S) const override;
|
||||
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override;
|
||||
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
|
||||
|
|
@ -1212,6 +1213,7 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
|
|||
|
||||
AArch64TargetInfo::AArch64TargetInfo() {
|
||||
CopyRel = R_AARCH64_COPY;
|
||||
RelativeRel = R_AARCH64_RELATIVE;
|
||||
IRelativeRel = R_AARCH64_IRELATIVE;
|
||||
GotRel = R_AARCH64_GLOB_DAT;
|
||||
PltRel = R_AARCH64_JUMP_SLOT;
|
||||
|
|
@ -1319,6 +1321,10 @@ bool AArch64TargetInfo::needsCopyRelImpl(uint32_t Type) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool AArch64TargetInfo::needsDynRelative(unsigned Type) const {
|
||||
return Config->Shared && Type == R_AARCH64_ABS64;
|
||||
}
|
||||
|
||||
bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
|
||||
switch (Type) {
|
||||
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
||||
|
|
|
|||
|
|
@ -311,9 +311,16 @@ void Writer<ELFT>::scanRelocs(
|
|||
if (handleTlsRelocation<ELFT>(Type, Body, C, RI))
|
||||
continue;
|
||||
|
||||
if (Target->needsDynRelative(Type))
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true,
|
||||
Body, getAddend<ELFT>(RI)});
|
||||
if (Target->needsDynRelative(Type)) {
|
||||
// If Body is null it means the relocation is against a local symbol
|
||||
// and thus we need to pass the local symbol index instead.
|
||||
if (Body)
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true,
|
||||
Body, getAddend<ELFT>(RI)});
|
||||
else
|
||||
Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, false,
|
||||
SymIndex, getAddend<ELFT>(RI)});
|
||||
}
|
||||
|
||||
// MIPS has a special rule to create GOTs for local symbols.
|
||||
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true) &&
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
// REQUIRES: aarch64
|
||||
// RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o
|
||||
|
||||
// Creates a R_AARCH64_ABS64 relocation against _foo. It will be used on a
|
||||
// shared object to check for a dynamic relocation creation.
|
||||
.globl _foo
|
||||
_foo:
|
||||
ret
|
||||
_foo_init_array:
|
||||
.xword _foo
|
||||
|
||||
// RUN: ld.lld -shared -o %t.so %t.o
|
||||
// RUN: llvm-readobj -symbols -dyn-relocations %t.so | FileCheck %s
|
||||
|
||||
// CHECK: Dynamic Relocations {
|
||||
// CHECK-NEXT: {{.*}} R_AARCH64_RELATIVE - [[FOO_ADDR:[0-9xa-f]+]]
|
||||
|
||||
// CHECK: Symbols [
|
||||
// CHECK: Symbol {
|
||||
// CHECK: Name: _foo
|
||||
// CHECK: Value: [[FOO_ADDR]]
|
||||
Loading…
Reference in New Issue