[lld] r241192 - [ELF/AArch64] Initial General-dynamic TLS support

Adhemerval Zanella adhemerval.zanella at linaro.org
Wed Jul 1 14:35:40 PDT 2015


Author: azanella
Date: Wed Jul  1 16:35:39 2015
New Revision: 241192

URL: http://llvm.org/viewvc/llvm-project?rev=241192&view=rev
Log:
[ELF/AArch64] Initial General-dynamic TLS support

This patch adds initial general-dynamic TLS support for AArch64.  Currently
no optimization is done to realx for more performance-wise models (initial-exec
or local-exec).  This patch also only currently handles correctly executable
generation, although priliminary DSO support through PLT specific creation
is also added.

With this change clang/llvm bootstrap with lld is possible in static configuration
(some DSO creation fails due missing Linker script support, not AArch64 specific),
although make check also shows some issues.

Added:
    lld/trunk/test/elf/AArch64/Inputs/general-dyn-tls-0.yaml
    lld/trunk/test/elf/AArch64/general-dyn-tls-0.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
    lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
    lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp

Modified: lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp?rev=241192&r1=241191&r2=241192&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationHandler.cpp Wed Jul  1 16:35:39 2015
@@ -399,6 +399,60 @@ static void relocR_AARCH64_TLSLE_ADD_TPR
   write32le(location, result | read32le(location));
 }
 
+/// \brief R_AARCH64_TLSDESC_ADR_PAGE21 - Page(G(GTLSDESC(S+A))) - Page(P)
+static std::error_code relocR_AARCH64_TLSDESC_ADR_PAGE21(uint8_t *location,
+                                                         uint64_t P, uint64_t S,
+                                                         int64_t A) {
+  int64_t result = page(S + A) - page(P);
+  if (!isInt<32>(result))
+    return make_out_of_range_reloc_error();
+  result = result >> 12;
+  uint32_t immlo = result & 0x3;
+  uint32_t immhi = result & 0x1FFFFC;
+  immlo = immlo << 29;
+  immhi = immhi << 3;
+  DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+        llvm::dbgs() << " S: " << Twine::utohexstr(S);
+        llvm::dbgs() << " A: " << Twine::utohexstr(A);
+        llvm::dbgs() << " P: " << Twine::utohexstr(P);
+        llvm::dbgs() << " immhi: " << Twine::utohexstr(immhi);
+        llvm::dbgs() << " immlo: " << Twine::utohexstr(immlo);
+        llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+  write32le(location, immlo | immhi | read32le(location));
+  return std::error_code();
+}
+
+/// \brief R_AARCH64_TLSDESC_LD64_LO12_NC - G(GTLSDESC(S+A)) -> S + A
+static std::error_code relocR_AARCH64_TLSDESC_LD64_LO12_NC(uint8_t *location,
+                                                           uint64_t P,
+                                                           uint64_t S,
+                                                           int64_t A) {
+  int32_t result = S + A;
+  DEBUG(llvm::dbgs() << " S: " << Twine::utohexstr(S);
+        llvm::dbgs() << " A: " << Twine::utohexstr(A);
+        llvm::dbgs() << " P: " << Twine::utohexstr(P);
+        llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+  if ((result & 0x7) != 0)
+    return make_unaligned_range_reloc_error();
+  result &= 0xFF8;
+  result <<= 7;
+  write32le(location, result | read32le(location));
+  return std::error_code();
+}
+
+/// \brief R_AARCH64_TLSDESC_ADD_LO12_NC - G(GTLSDESC(S+A)) -> S + A
+static void relocR_AARCH64_TLSDESC_ADD_LO12_NC(uint8_t *location, uint64_t P,
+                                               uint64_t S, int64_t A) {
+  int32_t result = (int32_t)((S + A) & 0xFFF);
+  result <<= 10;
+  DEBUG(llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
+        llvm::dbgs() << " S: " << Twine::utohexstr(S);
+        llvm::dbgs() << " A: " << Twine::utohexstr(A);
+        llvm::dbgs() << " P: " << Twine::utohexstr(P);
+        llvm::dbgs() << " result: " << Twine::utohexstr(result) << "\n");
+  write32le(location, result | read32le(location));
+}
+
 std::error_code AArch64TargetRelocationHandler::applyRelocation(
     ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
     const Reference &ref) const {
@@ -428,13 +482,6 @@ std::error_code AArch64TargetRelocationH
     return relocR_AARCH64_PREL32(loc, reloc, target, addend);
   case R_AARCH64_PREL16:
     return relocR_AARCH64_PREL16(loc, reloc, target, addend);
-  // Runtime only relocations. Ignore here.
-  case R_AARCH64_RELATIVE:
-  case R_AARCH64_IRELATIVE:
-  case R_AARCH64_JUMP_SLOT:
-  case R_AARCH64_GLOB_DAT:
-  case R_AARCH64_TLS_TPREL64:
-    break;
   case R_AARCH64_ADR_PREL_PG_HI21:
     return relocR_AARCH64_ADR_PREL_PG_HI21(loc, reloc, target, addend);
   case R_AARCH64_ADR_PREL_LO21:
@@ -484,6 +531,24 @@ std::error_code AArch64TargetRelocationH
       relocR_AARCH64_TLSLE_ADD_TPREL_LO12_NC(loc, reloc, target + tpoffset,
                                              addend);
   }  break;
+  case R_AARCH64_TLSDESC_ADR_PAGE21:
+    return relocR_AARCH64_TLSDESC_ADR_PAGE21(loc, reloc, target, addend);
+  case R_AARCH64_TLSDESC_LD64_LO12_NC:
+    return relocR_AARCH64_TLSDESC_LD64_LO12_NC(loc, reloc, target, addend);
+  case R_AARCH64_TLSDESC_ADD_LO12_NC:
+    relocR_AARCH64_TLSDESC_ADD_LO12_NC(loc, reloc, target, addend);
+    break;
+  case R_AARCH64_TLSDESC_CALL:
+    // Relaxation only to optimize TLS access. Ignore for now.
+    break;
+  // Runtime only relocations. Ignore here.
+  case R_AARCH64_RELATIVE:
+  case R_AARCH64_IRELATIVE:
+  case R_AARCH64_JUMP_SLOT:
+  case R_AARCH64_GLOB_DAT:
+  case R_AARCH64_TLS_TPREL64:
+  case R_AARCH64_TLSDESC:
+    break;
   default:
     return make_unhandled_reloc_error();
   }

Modified: lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp?rev=241192&r1=241191&r2=241192&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64RelocationPass.cpp Wed Jul  1 16:35:39 2015
@@ -31,6 +31,13 @@ using namespace llvm::ELF;
 // .got values
 static const uint8_t AArch64GotAtomContent[8] = {0};
 
+// tls descriptor .got values, the layout is:
+// struct tlsdesc {
+//   ptrdiff_t (*entry) (struct tlsdesc *);
+//   void *arg;
+// };
+static const uint8_t AArch64TlsdescGotAtomContent[16] = {0};
+
 // .plt value (entry 0)
 static const uint8_t AArch64Plt0AtomContent[32] = {
     0xf0, 0x7b, 0xbf, 0xa9, // stp	x16, x30, [sp,#-16]!
@@ -51,6 +58,18 @@ static const uint8_t AArch64PltAtomConte
     0x20, 0x02, 0x1f, 0xd6  // br   x17
 };
 
+// .plt tlsdesc values
+static const uint8_t AArch64PltTlsdescAtomContent[32] = {
+    0xe2, 0x0f, 0xbf, 0xa9, // stp  x2, x3, [sp, #-16]
+    0x02, 0x00, 0x00, 0x90, // adpr x2, 0
+    0x03, 0x00, 0x00, 0x90, // adpr x3, 0
+    0x42, 0x00, 0x40, 0xf9, // ldr  x2, [x2, #0]
+    0x63, 0x00, 0x00, 0x91, // add  x3, x3, 0
+    0x40, 0x00, 0x1f, 0xd6, // br   x2
+    0x1f, 0x20, 0x03, 0xd5, // nop
+    0x1f, 0x20, 0x03, 0xd5  // nop
+};
+
 namespace {
 
 /// \brief Atoms that are used by AArch64 dynamic linking
@@ -72,6 +91,16 @@ public:
   AArch64GOTPLTAtom(const File &f) : AArch64GOTAtom(f, ".got.plt") {}
 };
 
+class AArch64TLSDESCGOTAtom : public AArch64GOTPLTAtom {
+public:
+  AArch64TLSDESCGOTAtom(const File &f) : AArch64GOTPLTAtom(f) {}
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return ArrayRef<uint8_t>(AArch64TlsdescGotAtomContent, 16);
+  }
+};
+
+
 class AArch64PLT0Atom : public PLT0Atom {
 public:
   AArch64PLT0Atom(const File &f) : PLT0Atom(f) {}
@@ -89,6 +118,15 @@ public:
   }
 };
 
+class AArch64PLTTLSDESCAtom : public PLTAtom {
+public:
+  AArch64PLTTLSDESCAtom(const File &f) : PLTAtom(f, ".plt") {}
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return ArrayRef<uint8_t>(AArch64PltTlsdescAtomContent, 32);
+  }
+};
+
 class ELFPassFile : public SimpleFile {
 public:
   ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
@@ -153,6 +191,11 @@ template <class Derived> class AArch64Re
     case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
       static_cast<Derived *>(this)->handleGOTTPREL(ref);
       break;
+    case R_AARCH64_TLSDESC_ADR_PAGE21:
+    case R_AARCH64_TLSDESC_LD64_LO12_NC:
+    case R_AARCH64_TLSDESC_ADD_LO12_NC:
+      static_cast<Derived *>(this)->handleTLSDESC(ref);
+      break;
     }
   }
 
@@ -212,8 +255,41 @@ protected:
   /// \brief Create a GOT TPREL entry and change the relocation to a PC32 to
   /// the GOT.
   std::error_code handleGOTTPREL(const Reference &ref) {
-    if (isa<DefinedAtom>(ref.target())) {
+    if (isa<DefinedAtom>(ref.target()))
       const_cast<Reference &>(ref).setTarget(getGOTTPREL(ref.target()));
+    return std::error_code();
+  }
+
+  /// \brief Generates a double GOT entry with R_AARCH64_TLSDESC dynamic
+  /// relocation reference.  Since the dynamic relocation is resolved
+  /// lazily so the GOT associated should be in .got.plt.
+  const GOTAtom *getTLSDESCPLTEntry(const Atom *da) {
+    auto got = _gotMap.find(da);
+    if (got != _gotMap.end())
+      return got->second;
+    auto ga = new (_file._alloc) AArch64TLSDESCGOTAtom(_file);
+    ga->addReferenceELF_AArch64(R_AARCH64_TLSDESC, 0, da, 0);
+    auto pa = new (_file._alloc) AArch64PLTTLSDESCAtom(_file);
+    pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 4, ga, 0);
+    pa->addReferenceELF_AArch64(R_AARCH64_ADR_PREL_PG_HI21, 8, ga, 0);
+    pa->addReferenceELF_AArch64(R_AARCH64_LDST64_ABS_LO12_NC, 12, ga, 0);
+    pa->addReferenceELF_AArch64(R_AARCH64_ADD_ABS_LO12_NC, 16, ga, 0);
+#ifndef NDEBUG
+    ga->_name = "__got_tlsdesc_";
+    ga->_name += da->name();
+    pa->_name = "__plt_tlsdesc_";
+    pa->_name += da->name();
+#endif
+    _gotMap[da] = ga;
+    _pltMap[da] = pa;
+    _tlsdescVector.push_back(ga);
+    _pltVector.push_back(pa);
+    return ga;
+  }
+
+  std::error_code handleTLSDESC(const Reference &ref) {
+    if (isa<DefinedAtom>(ref.target())) {
+      const_cast<Reference &>(ref).setTarget(getTLSDESCPLTEntry(ref.target()));
     }
     return std::error_code();
   }
@@ -311,6 +387,11 @@ public:
       got->setOrdinal(ordinal++);
       mf.addAtom(*got);
     }
+    // Add any tlsdesc GOT relocation after default PLT and iFUNC entries.
+    for (auto &tlsdesc : _tlsdescVector) {
+      tlsdesc->setOrdinal(ordinal++);
+      mf.addAtom(*tlsdesc);
+    }
     for (auto obj : _objectVector) {
       obj->setOrdinal(ordinal++);
       mf.addAtom(*obj);
@@ -335,6 +416,7 @@ protected:
 
   /// \brief the list of GOT/PLT atoms
   std::vector<GOTAtom *> _gotVector;
+  std::vector<GOTAtom *> _tlsdescVector;
   std::vector<PLTAtom *> _pltVector;
   std::vector<ObjectAtom *> _objectVector;
 

Modified: lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp?rev=241192&r1=241191&r2=241192&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/AArch64/AArch64SectionChunks.cpp Wed Jul  1 16:35:39 2015
@@ -27,7 +27,8 @@ const AtomLayout *AArch64GOTSection::app
     if (r->kindNamespace() != Reference::KindNamespace::ELF)
       continue;
     assert(r->kindArch() == Reference::KindArch::AArch64);
-    if (r->kindValue() == R_AARCH64_TLS_TPREL64)
+    if ((r->kindValue() == R_AARCH64_TLS_TPREL64) ||
+        (r->kindValue() == R_AARCH64_TLSDESC))
       _tlsMap[r->target()] = _tlsMap.size();
   }
 

Added: lld/trunk/test/elf/AArch64/Inputs/general-dyn-tls-0.yaml
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/AArch64/Inputs/general-dyn-tls-0.yaml?rev=241192&view=auto
==============================================================================
--- lld/trunk/test/elf/AArch64/Inputs/general-dyn-tls-0.yaml (added)
+++ lld/trunk/test/elf/AArch64/Inputs/general-dyn-tls-0.yaml Wed Jul  1 16:35:39 2015
@@ -0,0 +1,65 @@
+---
+FileHeader:      
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_AARCH64
+Sections:        
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         FF4300D1E00F00B900040011E103002A48D03BD50801009108010091000100B9E10B00B9FF430091C0035FD6
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:     
+      - Offset:          0x0000000000000014
+        Symbol:          var
+        Type:            R_AARCH64_TLSLE_ADD_TPREL_HI12
+      - Offset:          0x0000000000000018
+        Symbol:          var
+        Type:            R_AARCH64_TLSLE_ADD_TPREL_LO12_NC
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .tbss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC, SHF_TLS ]
+    AddressAlign:    0x0000000000000004
+    Content:         00636C61
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+Symbols:         
+  Local:           
+#    - Name:            test_tls.c
+#      Type:            STT_FILE
+    - Name:            '$d.1'
+      Section:         .tbss
+    - Name:            '$x.0'
+      Section:         .text
+    - Name:            .tbss
+      Type:            STT_TLS
+      Section:         .tbss
+  Global:          
+    - Name:            foo
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000002C
+    - Name:            var
+      Type:            STT_TLS
+      Section:         .tbss
+      Size:            0x0000000000000004
+...

Added: lld/trunk/test/elf/AArch64/general-dyn-tls-0.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/AArch64/general-dyn-tls-0.test?rev=241192&view=auto
==============================================================================
--- lld/trunk/test/elf/AArch64/general-dyn-tls-0.test (added)
+++ lld/trunk/test/elf/AArch64/general-dyn-tls-0.test Wed Jul  1 16:35:39 2015
@@ -0,0 +1,104 @@
+# Check for correct offsets when handling relocations for general dynamic TLS
+# access in executable binaries.
+#
+# The test case was generated from following code snippet:
+#
+# == test_tls.c ==
+#
+# __thread int var;
+# void foo (int x) {
+#   var = x + 1;
+# }
+#
+# == test_main.c ==
+# #include <stdio.h>
+#
+# extern __thread int var;
+# extern void foo (int);
+#
+# int main () {
+#   foo (10);
+#   return var;
+# }
+#
+# The objects are compiled with -fpic.
+
+#RUN: yaml2obj -format=elf %p/Inputs/general-dyn-tls-0.yaml -o=%t-t1.o
+#RUN: yaml2obj -format=elf %s -o %t-t0.o
+#RUN: lld -flavor gnu -target arm64 --noinhibit-exec -o %t.exe %t-t0.o %t-t1.o
+#RUN: llvm-readobj -relocations %t.exe | FileCheck %s -check-prefix=CHECKRELOCATION
+#RUN: llvm-objdump -s -t %t.exe        | FileCheck %s
+
+#CHECKRELOCATION: Relocations [
+#CHECKRELOCATION:  .rela.dyn {
+#CHECKRELOCATION:    0x401090 R_AARCH64_TLSDESC - 0x0
+#CHECKRELOCATION: }
+
+#CHECK: Contents of section .text:
+#CHECK:      400230 a8c31fb8 40018052 0b000094 000000b0  .... at ..R........
+#                                              \_        adrp    x0, 401000 <_DYNAMIC> (R_AARCH64_TLSDESC_ADR_PAGE21)
+#CHECK-NEXT: 400240 014840f9 00400291 20003fd6 49d03bd5  .H at ..@.. .?.I.;.
+#                   \_       |        |                  ldr     x1, [x0,#144]         (R_AARCH64_TLSDESC_LD64_LO12_NC)
+#                            \_       |                  add     x0, x0, #0x90         (R_AARCH64_TLSDESC_ADD_LO12_NC)
+#                                     \_                 blr     x1                    (R_AARCH64_TLSDESC_CALL)
+
+---
+FileHeader:      
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_AARCH64
+Sections:        
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         FD7BBFA9FD030091FF4300D1E8031F2AA8C31FB8400180520000009400000090010040F90000009120003FD649D03BD5286960B8E003082ABF030091FD7BC1A8C0035FD6
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:     
+      - Offset:          0x0000000000000018
+        Symbol:          foo
+        Type:            R_AARCH64_CALL26
+      - Offset:          0x000000000000001C
+        Symbol:          var
+        Type:            R_AARCH64_TLSDESC_ADR_PAGE21
+      - Offset:          0x0000000000000020
+        Symbol:          var
+        Type:            R_AARCH64_TLSDESC_LD64_LO12_NC
+      - Offset:          0x0000000000000024
+        Symbol:          var
+        Type:            R_AARCH64_TLSDESC_ADD_LO12_NC
+      - Offset:          0x0000000000000028
+        Symbol:          var
+        Type:            R_AARCH64_TLSDESC_CALL
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+Symbols:         
+  Local:           
+    - Name:            '$x.0'
+      Section:         .text
+  Global:          
+    - Name:            foo
+    - Name:            main
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x0000000000000044
+    - Name:            var
+      Type:            STT_TLS





More information about the llvm-commits mailing list