[lld] 5a5a075 - [LLD][ELF][Hexagon] Support GDPLT transforms

Sid Manning via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 13 09:02:33 PDT 2020


Author: Sid Manning
Date: 2020-03-13T11:02:11-05:00
New Revision: 5a5a075c5b19b9024f53ecd03460c6e379798893

URL: https://github.com/llvm/llvm-project/commit/5a5a075c5b19b9024f53ecd03460c6e379798893
DIFF: https://github.com/llvm/llvm-project/commit/5a5a075c5b19b9024f53ecd03460c6e379798893.diff

LOG: [LLD][ELF][Hexagon] Support GDPLT transforms

Hexagon ABI specifies that call x at gdplt is transformed to call __tls_get_addr.

Example:
     call x at gdplt
is changed to
     call __tls_get_addr

When x is an external tls variable.

Differential Revision: https://reviews.llvm.org/D74443

Added: 
    lld/test/ELF/hexagon-tls-gd-xform.s

Modified: 
    lld/ELF/Arch/Hexagon.cpp
    lld/ELF/Relocations.cpp
    lld/ELF/Relocations.h
    lld/ELF/Writer.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp
index b1ec1579759d..730c47a88dfd 100644
--- a/lld/ELF/Arch/Hexagon.cpp
+++ b/lld/ELF/Arch/Hexagon.cpp
@@ -119,6 +119,7 @@ RelExpr Hexagon::getRelExpr(RelType type, const Symbol &s,
   case R_HEX_PLT_B22_PCREL:
   case R_HEX_B22_PCREL_X:
   case R_HEX_B32_PCREL_X:
+  case R_HEX_GD_PLT_B22_PCREL:
     return R_PLT_PC;
   case R_HEX_IE_32_6_X:
   case R_HEX_IE_16_X:
@@ -303,6 +304,7 @@ void Hexagon::relocate(uint8_t *loc, const Relocation &rel,
   case R_HEX_B15_PCREL_X:
     or32le(loc, applyMask(0x00df20fe, val & 0x3f));
     break;
+  case R_HEX_GD_PLT_B22_PCREL:
   case R_HEX_B22_PCREL:
   case R_HEX_PLT_B22_PCREL:
     checkInt(loc, val, 22, rel);

diff  --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 280173c5420e..59c9ecf0019d 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1980,6 +1980,44 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
   return addressesChanged;
 }
 
+// The following aid in the conversion of call x at GDPLT to call __tls_get_addr
+// hexagonNeedsTLSSymbol scans for relocations would require a call to
+// __tls_get_addr.
+// hexagonTLSSymbolUpdate rebinds the relocation to __tls_get_addr.
+bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections) {
+  bool needTlsSymbol = false;
+  forEachInputSectionDescription(
+      outputSections, [&](OutputSection *os, InputSectionDescription *isd) {
+        for (InputSection *isec : isd->sections)
+          for (Relocation &rel : isec->relocations)
+            if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) {
+              needTlsSymbol = true;
+              return;
+            }
+      });
+  return needTlsSymbol;
+}
+
+void hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections) {
+  Symbol *sym = symtab->find("__tls_get_addr");
+  if (!sym)
+    return;
+  bool needEntry = true;
+  forEachInputSectionDescription(
+      outputSections, [&](OutputSection *os, InputSectionDescription *isd) {
+        for (InputSection *isec : isd->sections)
+          for (Relocation &rel : isec->relocations)
+            if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) {
+              if (needEntry) {
+                addPltEntry(in.plt, in.gotPlt, in.relaPlt, target->pltRel,
+                            *sym);
+                needEntry = false;
+              }
+              rel.sym = sym;
+            }
+      });
+}
+
 template void scanRelocations<ELF32LE>(InputSectionBase &);
 template void scanRelocations<ELF32BE>(InputSectionBase &);
 template void scanRelocations<ELF64LE>(InputSectionBase &);

diff  --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 4069fc5f4786..b3181b67ad0e 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -115,6 +115,9 @@ template <class ELFT> void scanRelocations(InputSectionBase &);
 
 template <class ELFT> void reportUndefinedSymbols();
 
+void hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections);
+bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
+
 class ThunkSection;
 class Thunk;
 struct InputSectionDescription;

diff  --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index c916f35cc2b4..e172b708afcf 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1592,6 +1592,10 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
   ARMErr657417Patcher a32p;
   script->assignAddresses();
 
+  // Converts call x at GDPLT to call __tls_get_addr
+  if (config->emachine == EM_HEXAGON)
+    hexagonTLSSymbolUpdate(outputSections);
+
   int assignPasses = 0;
   for (;;) {
     bool changed = target->needsThunks && tc.createThunks(outputSections);
@@ -1849,6 +1853,15 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
       sec->addrExpr = [=] { return i->second; };
   }
 
+  // With the outputSections available check for GDPLT relocations
+  // and add __tls_get_addr symbol if needed.
+  if (config->emachine == EM_HEXAGON && hexagonNeedsTLSSymbol(outputSections)) {
+    Symbol *sym = symtab->addSymbol(Undefined{
+        nullptr, "__tls_get_addr", STB_GLOBAL, STV_DEFAULT, STT_NOTYPE});
+    sym->isPreemptible = true;
+    partitions[0].dynSymTab->addSymbol(sym);
+  }
+
   // This is a bit of a hack. A value of 0 means undef, so we set it
   // to 1 to make __ehdr_start defined. The section number is not
   // particularly relevant.

diff  --git a/lld/test/ELF/hexagon-tls-gd-xform.s b/lld/test/ELF/hexagon-tls-gd-xform.s
new file mode 100644
index 000000000000..65aeb118fcb3
--- /dev/null
+++ b/lld/test/ELF/hexagon-tls-gd-xform.s
@@ -0,0 +1,47 @@
+# REQUIRES: hexagon
+# RUN: llvm-mc -filetype=obj -defsym GDPLT=1 -triple=hexagon-unknown-elf %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t1.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: ld.lld -shared %t1.o -o %t1.so
+# RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex %t.so | \
+# RUN:   FileCheck --check-prefix=CHECK_GDPLT %s
+# RUN: llvm-objdump -d --no-show-raw-insn --print-imm-hex %t1.so | FileCheck %s
+# RUN: llvm-readobj -r %t.so | FileCheck -check-prefix=RELA_GDPLT  %s
+
+## Make sure __tls_get_addr is not present unless there is a GDPLT relocation.
+# RUN: llvm-readobj -r %t1.so | FileCheck -check-prefix=RELA \
+# RUN:   --implicit-check-not="__tls_get_addr" %s
+
+.globl _start
+.type _start, @function
+
+_start:
+.ifdef GDPLT
+                        call x at gdplt
+# CHECK_GDPLT:  101ec: { call 0x10220 }
+.else
+                  call x
+# CHECK:  101b8: { call 0x101e0 }
+.endif
+
+# CHECK_GDPLT:        10220: { immext(#0x20040)
+# CHECK_GDPLT-NEXT:   10224:   r14 = add(pc,##0x2007c) }
+# CHECK_GDPLT-NEXT:   10228: { r28 = memw(r14+#0x0) }
+# CHECK_GDPLT-NEXT:   1022c: { jumpr r28 }
+
+
+## Looking at the above check, 0x10220+0x2007c must equal the entry for
+##  __tls_get_addr, 0x3029C
+
+# RELA_GDPLT: Relocations [
+# RELA_GDPLT-NEXT:  Section (5) .rela.plt {
+# RELA_GDPLT-NEXT:    0x30298 R_HEX_JMP_SLOT x 0x0
+# RELA_GDPLT-NEXT:    0x3029C R_HEX_JMP_SLOT __tls_get_addr 0x0
+# RELA_GDPLT-NEXT:  }
+# RELA_GDPLT-NEXT:]
+
+# RELA: Relocations [
+# RELA-NEXT:  Section (5) .rela.plt {
+# RELA-NEXT:    0x30258 R_HEX_JMP_SLOT x 0x0
+# RELA-NEXT:  }
+# RELA-NEXT:]


        


More information about the llvm-commits mailing list