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), Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -262,6 +262,13 @@ 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. + auto File = Rel.OffsetSec->getFile(); + auto LocalSym = File->getLocalSymbol(Rel.SymIndex); + VA = getLocalTarget(*File, *LocalSym, 0); + } reinterpret_cast(P)->r_addend = Rel.Addend + VA; } @@ -865,7 +872,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. @@ -878,10 +884,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 @@ -891,8 +909,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; } @@ -1653,5 +1671,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.h =================================================================== --- ELF/Target.h +++ ELF/Target.h @@ -54,6 +54,7 @@ virtual bool isSizeRel(uint32_t Type) const; virtual bool needsDynRelative(unsigned Type) const { return false; } + virtual uint64_t getDynRelativeAddend(unsigned Type, uint64_t Addend) const; virtual bool needsGot(uint32_t Type, SymbolBody &S) const; enum PltNeed { Plt_No, Plt_Explicit, Plt_Implicit }; Index: ELF/Target.cpp =================================================================== --- ELF/Target.cpp +++ ELF/Target.cpp @@ -164,6 +164,7 @@ int32_t Index, unsigned RelOff) const override; bool needsGot(uint32_t Type, SymbolBody &S) const override; PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override; + uint64_t getDynRelativeAddend(unsigned Type, uint64_t Addend) const override; void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P, uint64_t SA, uint64_t ZA = 0, uint8_t *PairedLoc = nullptr) const override; @@ -181,6 +182,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; @@ -276,6 +278,11 @@ bool TargetInfo::isRelRelative(uint32_t Type) const { return true; } bool TargetInfo::isSizeRel(uint32_t Type) const { return false; } +uint64_t TargetInfo::getDynRelativeAddend(unsigned Type, + uint64_t Addend) const { + return Addend; +} + bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return false; } TargetInfo::PltNeed TargetInfo::needsPlt(uint32_t Type, @@ -1057,6 +1064,13 @@ return Plt_No; } +uint64_t PPC64TargetInfo::getDynRelativeAddend(unsigned Type, + uint64_t Addend) const { + if (Type == R_PPC64_TOC) + return getPPC64TocBase() + Addend; + return Addend; +} + bool PPC64TargetInfo::isRelRelative(uint32_t Type) const { switch (Type) { default: @@ -1188,6 +1202,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 +1291,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,17 @@ 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. + uintX_t Addend = Target->getDynRelativeAddend(Type, getAddend(RI)); + if (Body) + Out::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true, + Body, Addend}); + else + Out::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, false, + SymIndex, Addend}); + } // 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]]