diff options
-rw-r--r-- | lld/ELF/OutputSections.cpp | 47 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 14 | ||||
-rw-r--r-- | lld/ELF/Target.cpp | 6 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 13 | ||||
-rw-r--r-- | lld/test/ELF/aarch64-abs64-dyn.s | 21 |
5 files changed, 90 insertions, 11 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index c7fd9919091..3945d880ebf 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -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); +} + +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) - + 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); } } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index a3a80db42ea..8b0b54dcdfc 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -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; @@ -207,6 +214,12 @@ template <class ELFT> struct DynamicReloc { 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) : Type(Type), OKind(Off_Sec), OffsetSec(OffsetSec), @@ -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; diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index 575f7022e21..1c5c57dd8ae 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 a356eeae945..525bb30d47a 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -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) && diff --git a/lld/test/ELF/aarch64-abs64-dyn.s b/lld/test/ELF/aarch64-abs64-dyn.s new file mode 100644 index 00000000000..f9605efd3a1 --- /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]] |