[lld] r261651 - [lld] [ELF/AArch64] Fix R_AARCH64_ABS64 in Shared mode

Adhemerval Zanella via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 23 08:54:41 PST 2016


Author: azanella
Date: Tue Feb 23 10:54:40 2016
New Revision: 261651

URL: http://llvm.org/viewvc/llvm-project?rev=261651&view=rev
Log:
[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.

Added:
    lld/trunk/test/ELF/aarch64-abs64-dyn.s
Modified:
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=261651&r1=261650&r2=261651&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Tue Feb 23 10:54:40 2016
@@ -253,11 +253,18 @@ template <class ELFT> void RelocationSec
 
     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
                         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
   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
   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(cons
 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);
 }
 }

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=261651&r1=261650&r2=261651&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Tue Feb 23 10:54:40 2016
@@ -53,6 +53,12 @@ getLocalRelTarget(const ObjectFile<ELFT>
                   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 DynamicRelo
   } 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 DynamicRelo
         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;

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=261651&r1=261650&r2=261651&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Tue Feb 23 10:54:40 2016
@@ -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_
 
 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
   }
 }
 
+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:

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=261651&r1=261650&r2=261651&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Tue Feb 23 10:54:40 2016
@@ -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) &&

Added: lld/trunk/test/ELF/aarch64-abs64-dyn.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/aarch64-abs64-dyn.s?rev=261651&view=auto
==============================================================================
--- lld/trunk/test/ELF/aarch64-abs64-dyn.s (added)
+++ lld/trunk/test/ELF/aarch64-abs64-dyn.s Tue Feb 23 10:54:40 2016
@@ -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]]




More information about the llvm-commits mailing list