From 668ad0ffcb49ec04beede54d07652f4dc538fd0f Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Tue, 23 Feb 2016 16:54:40 +0000 Subject: [PATCH] [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 --- lld/ELF/OutputSections.cpp | 47 +++++++++++++++++++++++++++++++++------- lld/ELF/OutputSections.h | 14 ++++++++++++ lld/ELF/Target.cpp | 6 +++++ lld/ELF/Writer.cpp | 13 ++++++++--- lld/test/ELF/aarch64-abs64-dyn.s | 21 ++++++++++++++++++ 5 files changed, 90 insertions(+), 11 deletions(-) create mode 100644 lld/test/ELF/aarch64-abs64-dyn.s diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index c7fd991..3945d88 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -253,11 +253,18 @@ template void RelocationSection::writeTo(uint8_t *Buf) { if (IsRela) { uintX_t VA = 0; - if (Rel.UseSymVA) + if (Rel.UseSymVA) { VA = Sym->getVA(); - 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 *File = Rel.OffsetSec->getFile(); + const Elf_Sym *LocalSym = File->getLocalSymbol(Rel.SymIndex); + VA = getLocalTarget(*File, *LocalSym, 0); + } reinterpret_cast(P)->r_addend = Rel.Addend + VA; } @@ -862,7 +869,6 @@ elf2::getLocalRelTarget(const ObjectFile &File, const Elf_Rel_Impl &RI, typename ELFFile::uintX_t Addend) { typedef typename ELFFile::Elf_Sym Elf_Sym; - typedef typename ELFFile::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 &File, if (!Sym) fatal("Unsupported relocation without symbol"); - InputSectionBase *Section = File.getSection(*Sym); + return getLocalTarget(File, *Sym, Addend); +} + +template +typename ELFFile::uintX_t +elf2::getLocalTarget(const ObjectFile &File, + const typename ELFFile::Elf_Sym &Sym, + typename ELFFile::uintX_t Addend) { + typedef typename ELFFile::uintX_t uintX_t; + + InputSectionBase *Section = File.getSection(Sym); + if (!Section) + return Addend; - if (Sym->getType() == STT_TLS) - return (Section->OutSec->getVA() + Section->getOffset(*Sym) + Addend) - + if (Sym.getType() == STT_TLS) + return (Section->OutSec->getVA() + Section->getOffset(Sym) + Addend) - Out::TlsPhdr->p_vaddr; // According to the ELF spec reference to a local symbol from outside @@ -888,8 +906,8 @@ elf2::getLocalRelTarget(const ObjectFile &File, if (Section == &InputSection::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 &, template uint64_t getLocalRelTarget(const ObjectFile &, const ELFFile::Elf_Rela &, uint64_t); + +template uint32_t getLocalTarget(const ObjectFile &, + const ELFFile::Elf_Sym &Sym, + uint32_t); +template uint32_t getLocalTarget(const ObjectFile &, + const ELFFile::Elf_Sym &Sym, + uint32_t); +template uint64_t getLocalTarget(const ObjectFile &, + const ELFFile::Elf_Sym &Sym, + uint64_t); +template uint64_t getLocalTarget(const ObjectFile &, + const ELFFile::Elf_Sym &Sym, + uint64_t); } } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index a3a80db..8b0b54d 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -53,6 +53,12 @@ getLocalRelTarget(const ObjectFile &File, const llvm::object::Elf_Rel_Impl &Rel, typename llvm::object::ELFFile::uintX_t Addend); +template +typename llvm::object::ELFFile::uintX_t +getLocalTarget(const ObjectFile &File, + const typename llvm::object::ELFFile::Elf_Sym &Sym, + typename llvm::object::ELFFile::uintX_t Addend); + bool canBePreempted(const SymbolBody *Body, bool NeedsGot); // This represents a section in an output file. @@ -187,6 +193,7 @@ template struct DynamicReloc { } OKind; SymbolBody *Sym = nullptr; + uint32_t SymIndex = 0; InputSectionBase *OffsetSec = nullptr; uintX_t OffsetInSec = 0; bool UseSymVA = false; @@ -207,6 +214,12 @@ template struct DynamicReloc { OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {} DynamicReloc(uint32_t Type, InputSectionBase *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 *OffsetSec, uintX_t OffsetInSec, InputSectionBase *TargetSec, uintX_t OffsetInTargetSec, uintX_t Addend) : Type(Type), OKind(Off_Sec), OffsetSec(OffsetSec), @@ -254,6 +267,7 @@ private: template class RelocationSection final : public OutputSectionBase { + typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; typedef typename llvm::object::ELFFile::Elf_Rela Elf_Rela; typedef typename llvm::object::ELFFile::uintX_t uintX_t; diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 575f702..1c5c57d 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -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: diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index a356eea..525bb30 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -311,9 +311,16 @@ void Writer::scanRelocs( if (handleTlsRelocation(Type, Body, C, RI)) continue; - if (Target->needsDynRelative(Type)) - Out::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true, - Body, getAddend(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::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true, + Body, getAddend(RI)}); + else + Out::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, false, + SymIndex, getAddend(RI)}); + } // MIPS has a special rule to create GOTs for local symbols. if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true) && diff --git a/lld/test/ELF/aarch64-abs64-dyn.s b/lld/test/ELF/aarch64-abs64-dyn.s new file mode 100644 index 0000000..f9605ef --- /dev/null +++ b/lld/test/ELF/aarch64-abs64-dyn.s @@ -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]] -- 2.7.4