Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -53,6 +53,12 @@ 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 @@ } OKind; SymbolBody *Sym = nullptr; + uint32_t SymIndex = 0; InputSectionBase *OffsetSec = nullptr; uintX_t OffsetInSec = 0; bool UseSymVA = false; @@ -207,6 +214,12 @@ 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 @@ 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; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -253,11 +253,18 @@ 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 @@ 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 @@ 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 @@ 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; } @@ -1646,5 +1664,18 @@ 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); } } Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -181,6 +181,7 @@ int32_t Index, unsigned RelOff) const override; unsigned getTlsGotRel(unsigned Type) const override; bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override; + bool needsDynRelative(unsigned Type) const override; bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override; bool needsGot(uint32_t Type, SymbolBody &S) const override; PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override; @@ -1188,6 +1189,7 @@ AArch64TargetInfo::AArch64TargetInfo() { CopyRel = R_AARCH64_COPY; + RelativeRel = R_AARCH64_RELATIVE; IRelativeRel = R_AARCH64_IRELATIVE; GotRel = R_AARCH64_GLOB_DAT; PltRel = R_AARCH64_JUMP_SLOT; @@ -1276,6 +1278,10 @@ Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; } +bool AArch64TargetInfo::needsDynRelative(unsigned Type) const { + return Config->Shared && Type == R_AARCH64_ABS64; +} + bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const { if (Config->Shared) return false; Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -310,9 +310,16 @@ 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) && Index: test/ELF/aarch64-abs64-dyn.s =================================================================== --- /dev/null +++ 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]]