[lld] [lld][Hexagon] Fix TLS GD PLT to only create PLT entry for __tls_get_addr (PR #180297)

Brian Cain via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 9 21:09:53 PST 2026


https://github.com/androm3da updated https://github.com/llvm/llvm-project/pull/180297

>From b354dca2ab9ab7b7ec0903dc0a1cd1bccb1fb4b7 Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Fri, 6 Feb 2026 14:41:47 -0800
Subject: [PATCH 1/2] [lld][Hexagon] Fix TLS GD PLT to only create PLT entry
 for __tls_get_addr

Previously, R_HEX_GD_PLT_* relocations would create PLT entries for TLS
symbols like 'foo' in addition to __tls_get_addr.

This fix skips NEEDS_PLT on TLS symbols with R_HEX_GD_PLT_*, creates
__tls_get_addr symbol earlier with NEEDS_PLT, changes  hexagonTLSSymbolUpdate
to only rebind relocations.

Also a test for the edge case where a GD_PLT relocation directly
references __tls_get_addr which previously caused a crash due to duplicate
PLT entry creation.
---
 lld/ELF/Relocations.cpp                      | 38 +++++++++++++-------
 lld/ELF/Relocations.h                        |  1 +
 lld/ELF/Writer.cpp                           | 26 +++++++++-----
 lld/test/ELF/hexagon-thunk-range-gdplt.s     | 36 +++++++------------
 lld/test/ELF/hexagon-tls-gd-nonpreemptible.s |  1 -
 lld/test/ELF/hexagon-tls-gd-plt-direct.s     | 35 ++++++++++++++++++
 lld/test/ELF/hexagon-tls-gd-xform.s          | 17 +++++----
 7 files changed, 100 insertions(+), 54 deletions(-)
 create mode 100644 lld/test/ELF/hexagon-tls-gd-plt-direct.s

diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 9ea5758eea8c2..e5e5416827228 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -978,7 +978,13 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
         sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
     }
   } else if (needsPlt(expr)) {
-    sym.setFlags(NEEDS_PLT);
+    // For Hexagon TLS GD PLT relocations (call foo at GDPLT), the PLT entry should
+    // be for __tls_get_addr, not the TLS symbol. hexagonTLSSymbolUpdate() will
+    // rebind these relocations to __tls_get_addr and create its PLT entry.
+    if (!(ctx.arg.emachine == EM_HEXAGON && sym.isTls() &&
+          (type == R_HEX_GD_PLT_B22_PCREL || type == R_HEX_GD_PLT_B22_PCREL_X ||
+           type == R_HEX_GD_PLT_B32_PCREL_X)))
+      sym.setFlags(NEEDS_PLT);
   } else if (LLVM_UNLIKELY(isIfunc)) {
     sym.setFlags(HAS_DIRECT_RELOC);
   }
@@ -2199,7 +2205,7 @@ bool ThunkCreator::createThunks(uint32_t pass,
 }
 
 // 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
+// hexagonNeedsTLSSymbol scans for relocations that would require a call to
 // __tls_get_addr.
 // hexagonTLSSymbolUpdate rebinds the relocation to __tls_get_addr.
 bool elf::hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections) {
@@ -2216,25 +2222,33 @@ bool elf::hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections) {
   return needTlsSymbol;
 }
 
+// Check if any input section has a TLS GD PLT relocation. This is used early
+// in the linking process before output sections are populated.
+bool elf::hexagonNeedsTLSSymbolEarly(Ctx &ctx) {
+  for (InputSectionBase *sec : ctx.inputSections) {
+    auto *isec = dyn_cast<InputSection>(sec);
+    if (!isec)
+      continue;
+    for (const Relocation &rel : isec->relocs())
+      if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC)
+        return true;
+  }
+  return false;
+}
+
 void elf::hexagonTLSSymbolUpdate(Ctx &ctx) {
   Symbol *sym = ctx.symtab->find("__tls_get_addr");
   if (!sym)
     return;
-  bool needEntry = true;
+  // Rebind TLS GD PLT relocations from the TLS symbol to __tls_get_addr.
+  // The PLT entry for __tls_get_addr should already be created by
+  // postScanRelocations since NEEDS_PLT is set on it.
   forEachInputSectionDescription(
       ctx.outputSections, [&](OutputSection *os, InputSectionDescription *isd) {
         for (InputSection *isec : isd->sections)
           for (Relocation &rel : isec->relocs())
-            if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) {
-              if (needEntry) {
-                if (sym->auxIdx == 0)
-                  sym->allocateAux(ctx);
-                addPltEntry(ctx, *ctx.in.plt, *ctx.in.gotPlt, *ctx.in.relaPlt,
-                            ctx.target->pltRel, *sym);
-                needEntry = false;
-              }
+            if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC)
               rel.sym = sym;
-            }
       });
 }
 
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index 680eb66e3356a..db312e5a35146 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -173,6 +173,7 @@ void addGotEntry(Ctx &ctx, Symbol &sym);
 
 void hexagonTLSSymbolUpdate(Ctx &ctx);
 bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
+bool hexagonNeedsTLSSymbolEarly(Ctx &ctx);
 
 bool isAbsolute(const Symbol &sym);
 
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 9220d73559b0b..eccf67c1a480f 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1920,6 +1920,17 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     // a linker-script-defined symbol is absolute.
     scanRelocations<ELFT>(ctx);
     reportUndefinedSymbols(ctx);
+
+    // For Hexagon TLS GD PLT relocations, create __tls_get_addr symbol before
+    // postScanRelocations so that its PLT entry is created at the right time.
+    if (ctx.arg.emachine == EM_HEXAGON && hexagonNeedsTLSSymbolEarly(ctx)) {
+      Symbol *sym =
+          ctx.symtab->addSymbol(Undefined{ctx.internalFile, "__tls_get_addr",
+                                          STB_GLOBAL, STV_DEFAULT, STT_NOTYPE});
+      sym->isPreemptible = true;
+      sym->setFlags(NEEDS_PLT);
+    }
+
     postScanRelocations(ctx);
 
     if (ctx.in.plt && ctx.in.plt->isNeeded())
@@ -2037,15 +2048,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
       sec->addrExpr = [=] { return i->second; };
   }
 
-  // With the ctx.outputSections available check for GDPLT relocations
-  // and add __tls_get_addr symbol if needed.
-  if (ctx.arg.emachine == EM_HEXAGON &&
-      hexagonNeedsTLSSymbol(ctx.outputSections)) {
-    Symbol *sym =
-        ctx.symtab->addSymbol(Undefined{ctx.internalFile, "__tls_get_addr",
-                                        STB_GLOBAL, STV_DEFAULT, STT_NOTYPE});
-    sym->isPreemptible = true;
-    ctx.partitions[0].dynSymTab->addSymbol(sym);
+  // Note: __tls_get_addr is now created earlier (before postScanRelocations)
+  // so that its PLT entry is created at the right time. We just need to add
+  // it to the dynamic symbol table here if it exists.
+  if (ctx.arg.emachine == EM_HEXAGON) {
+    if (Symbol *sym = ctx.symtab->find("__tls_get_addr"))
+      ctx.partitions[0].dynSymTab->addSymbol(sym);
   }
 
   // This is a bit of a hack. A value of 0 means undef, so we set it
diff --git a/lld/test/ELF/hexagon-thunk-range-gdplt.s b/lld/test/ELF/hexagon-thunk-range-gdplt.s
index 77fd0e5754568..f646e81026ce9 100644
--- a/lld/test/ELF/hexagon-thunk-range-gdplt.s
+++ b/lld/test/ELF/hexagon-thunk-range-gdplt.s
@@ -48,27 +48,29 @@ tls_var_distant:
 
 # CHECK: Disassembly of section .text:
 # CHECK:     <_start>:
-# CHECK-NEXT:   102d4:  { immext(#0x420100)
-# CHECK-NEXT:      r2 = add(pc,##0x420130) }
+# CHECK-NEXT:   102b0:  { immext(#0x420100)
+# CHECK-NEXT:      r2 = add(pc,##0x420104) }
 # CHECK-NEXT:    { immext(#0xfffeffc0)
 # CHECK-NEXT:      r0 = add(r2,##-0x10018) }
-# CHECK-NEXT:    { call 0x410360 <__tls_get_addr at plt> }
+# CHECK-NEXT:    { call 0x410310 <__tls_get_addr at plt> }
 # CHECK-NEXT:    { immext(#0xfffeffc0)
 # CHECK-NEXT:      r0 = add(r2,##-0x10010) }
-# CHECK-NEXT:    { call 0x410360 <__tls_get_addr at plt> }
+# CHECK-NEXT:    { call 0x410310 <__tls_get_addr at plt> }
 # CHECK-NEXT:    { jumpr r31 }
 
 # CHECK:     <more_code>:
-# CHECK-NEXT:   4102f8:  { immext(#0xfffeffc0)
+# CHECK-NEXT:   4102d4:  { immext(#0xfffeffc0)
 # CHECK-NEXT:      r0 = add(r2,##-0x10008) }
-# CHECK-NEXT:    { call 0x410360 <__tls_get_addr at plt> }
+# CHECK-NEXT:    { call 0x410310 <__tls_get_addr at plt> }
 # CHECK-NEXT:    { jumpr r31 }
 
-## Verify PLT entries are created for TLS
+## Verify PLT entry is created for __tls_get_addr
+## TLS symbols (tls_var_close, tls_var_far, tls_var_distant) should NOT have
+## PLT entries - only __tls_get_addr needs one.
 # CHECK: Disassembly of section .plt:
 # CHECK:      <.plt>:
-# CHECK-NEXT:   410310:  { immext(#0x200c0)
-# CHECK-NEXT:      r28 = add(pc,##0x200f4) }
+# CHECK-NEXT:   4102f0:  { immext(#0x200c0)
+# CHECK-NEXT:      r28 = add(pc,##0x200c4) }
 # CHECK-NEXT:    { r14 -= add(r28,#0x10)
 # CHECK-NEXT:      r15 = memw(r28+#0x8)
 # CHECK-NEXT:      r28 = memw(r28+#0x4) }
@@ -76,20 +78,8 @@ tls_var_distant:
 # CHECK-NEXT:      jumpr r28 }
 # CHECK-NEXT:    { trap0(#0xdb) }
 
-# CHECK:      <tls_var_far at plt>:
-# CHECK-NEXT:   410340:  { immext(#0x200c0)
-# CHECK-NEXT:      r14 = add(pc,##0x200d8) }
-# CHECK-NEXT:    { r28 = memw(r14+#0x0) }
-# CHECK-NEXT:    { jumpr r28 }
-
-# CHECK:      <tls_var_distant at plt>:
-# CHECK-NEXT:   410350:  { immext(#0x200c0)
-# CHECK-NEXT:      r14 = add(pc,##0x200cc) }
-# CHECK-NEXT:    { r28 = memw(r14+#0x0) }
-# CHECK-NEXT:    { jumpr r28 }
-
 # CHECK:      <__tls_get_addr at plt>:
-# CHECK-NEXT:   410360: { immext(#0x200c0)
-# CHECK-NEXT:      r14 = add(pc,##0x200c0) }
+# CHECK-NEXT:   410310: { immext(#0x20080)
+# CHECK-NEXT:      r14 = add(pc,##0x200b4) }
 # CHECK-NEXT:    { r28 = memw(r14+#0x0) }
 # CHECK-NEXT:    { jumpr r28 }
diff --git a/lld/test/ELF/hexagon-tls-gd-nonpreemptible.s b/lld/test/ELF/hexagon-tls-gd-nonpreemptible.s
index ff5e6dbaac710..ca84865e1dba1 100644
--- a/lld/test/ELF/hexagon-tls-gd-nonpreemptible.s
+++ b/lld/test/ELF/hexagon-tls-gd-nonpreemptible.s
@@ -14,7 +14,6 @@
 .type _start, @function
 
 # RELOC:      Section ({{.*}}) .rela.plt {
-# RELOC-NEXT:   R_HEX_JMP_SLOT - 0x0
 # RELOC-NEXT:   R_HEX_JMP_SLOT __tls_get_addr 0x0
 # RELOC-NEXT: }
 
diff --git a/lld/test/ELF/hexagon-tls-gd-plt-direct.s b/lld/test/ELF/hexagon-tls-gd-plt-direct.s
new file mode 100644
index 0000000000000..9d54fcae269b2
--- /dev/null
+++ b/lld/test/ELF/hexagon-tls-gd-plt-direct.s
@@ -0,0 +1,35 @@
+# REQUIRES: hexagon
+# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t.o
+# RUN: ld.lld -shared %t.o -o %t.so
+# RUN: llvm-readobj -r %t.so | FileCheck %s
+
+## This test verifies that lld doesn't crash when there's a direct GD_PLT
+## relocation against __tls_get_addr, which can happen when the assembler
+## incorrectly marks __tls_get_addr as STT_TLS due to the @GDPLT suffix.
+## The linker should handle this gracefully by not creating duplicate PLT
+## entries for __tls_get_addr.
+
+# CHECK:      Section ({{.*}}) .rela.dyn {
+# CHECK-NEXT:   R_HEX_DTPMOD_32 foo 0x0
+# CHECK-NEXT:   R_HEX_DTPREL_32 foo 0x0
+# CHECK-NEXT: }
+# CHECK:      Section ({{.*}}) .rela.plt {
+# CHECK-NEXT:   R_HEX_JMP_SLOT __tls_get_addr 0x0
+# CHECK-NEXT: }
+
+.globl _start
+.type _start, @function
+_start:
+  ## Use GD_GOT to set up TLS GOT entry for foo
+  r2 = add(pc, ##_GLOBAL_OFFSET_TABLE_ at PCREL)
+  r0 = add(r2, ##foo at GDGOT)
+  ## This creates GD_PLT relocations against __tls_get_addr directly
+  ## (not a TLS symbol), which used to cause an assertion failure
+  call ##__tls_get_addr at GDPLT
+  jumpr r31
+
+.section .tdata,"awT", at progbits
+.globl foo
+.type foo, @object
+foo:
+  .word 0x11111111
diff --git a/lld/test/ELF/hexagon-tls-gd-xform.s b/lld/test/ELF/hexagon-tls-gd-xform.s
index ade54e8a16fad..a87ec4bd61cdd 100644
--- a/lld/test/ELF/hexagon-tls-gd-xform.s
+++ b/lld/test/ELF/hexagon-tls-gd-xform.s
@@ -18,25 +18,24 @@
 _start:
 .ifdef GDPLT
                         call x at gdplt
-# CHECK_GDPLT:  101ec: { call 0x10220 <__tls_get_addr at plt> }
+# CHECK_GDPLT:  101e0: { call 0x10210 <__tls_get_addr at plt> }
 .else
                   call x
 # CHECK:  101b8: { call 0x101e0 <x at plt> }
 .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 }
+# CHECK_GDPLT:        10210: { immext(#0x20040)
+# CHECK_GDPLT-NEXT:   10214:   r14 = add(pc,##0x20078) }
+# CHECK_GDPLT-NEXT:   10218: { r28 = memw(r14+#0x0) }
+# CHECK_GDPLT-NEXT:   1021c: { jumpr r28 }
 
 
-## Looking at the above check, 0x10220+0x2007c must equal the entry for
-##  __tls_get_addr, 0x3029C
+## Looking at the above check, 0x10210+0x20078 must equal the entry for
+##  __tls_get_addr, 0x30288
 
 # 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:    0x30288 R_HEX_JMP_SLOT __tls_get_addr 0x0
 # RELA_GDPLT-NEXT:  }
 # RELA_GDPLT-NEXT:]
 

>From c0f234ce7f7cde5d2ceb4206c64e31b480c79770 Mon Sep 17 00:00:00 2001
From: Brian Cain <brian.cain at oss.qualcomm.com>
Date: Sat, 7 Feb 2026 12:03:13 -0800
Subject: [PATCH 2/2] review feedback

* Create __tls_get_addr during scanRelocations instead of
hexagonNeedsTLSSymbolEarly
* Use isInPlt guard
* Simplify hexagonTLSSymbolUpdate to only rebind relocations
* Fix test comment: no assertion failure, just duplicate JMP_SLOTs
---
 lld/ELF/Relocations.cpp                  | 58 ++++++++----------------
 lld/ELF/Relocations.h                    |  2 -
 lld/ELF/Writer.cpp                       | 16 +------
 lld/test/ELF/hexagon-tls-gd-plt-direct.s |  9 ++--
 4 files changed, 24 insertions(+), 61 deletions(-)

diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index e5e5416827228..46a190de5bf23 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -979,12 +979,24 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
     }
   } else if (needsPlt(expr)) {
     // For Hexagon TLS GD PLT relocations (call foo at GDPLT), the PLT entry should
-    // be for __tls_get_addr, not the TLS symbol. hexagonTLSSymbolUpdate() will
-    // rebind these relocations to __tls_get_addr and create its PLT entry.
-    if (!(ctx.arg.emachine == EM_HEXAGON && sym.isTls() &&
-          (type == R_HEX_GD_PLT_B22_PCREL || type == R_HEX_GD_PLT_B22_PCREL_X ||
-           type == R_HEX_GD_PLT_B32_PCREL_X)))
+    // be for __tls_get_addr, not the TLS symbol. Create __tls_get_addr here
+    // with NEEDS_PLT so its PLT entry is created during postScanRelocations.
+    // hexagonTLSSymbolUpdate() will rebind the relocations later.
+    if (ctx.arg.emachine == EM_HEXAGON && sym.isTls() &&
+        (type == R_HEX_GD_PLT_B22_PCREL || type == R_HEX_GD_PLT_B22_PCREL_X ||
+         type == R_HEX_GD_PLT_B32_PCREL_X)) {
+      Symbol *s = ctx.symtab->find("__tls_get_addr");
+      if (!s) {
+        s = ctx.symtab->addSymbol(Undefined{ctx.internalFile, "__tls_get_addr",
+                                            STB_GLOBAL, STV_DEFAULT,
+                                            STT_NOTYPE});
+        s->isPreemptible = true;
+      }
+      if (!s->isInPlt(ctx))
+        s->setFlags(NEEDS_PLT);
+    } else {
       sym.setFlags(NEEDS_PLT);
+    }
   } else if (LLVM_UNLIKELY(isIfunc)) {
     sym.setFlags(HAS_DIRECT_RELOC);
   }
@@ -2205,44 +2217,12 @@ bool ThunkCreator::createThunks(uint32_t pass,
 }
 
 // The following aid in the conversion of call x at GDPLT to call __tls_get_addr
-// hexagonNeedsTLSSymbol scans for relocations that would require a call to
-// __tls_get_addr.
-// hexagonTLSSymbolUpdate rebinds the relocation to __tls_get_addr.
-bool elf::hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections) {
-  bool needTlsSymbol = false;
-  forEachInputSectionDescription(
-      outputSections, [&](OutputSection *os, InputSectionDescription *isd) {
-        for (InputSection *isec : isd->sections)
-          for (Relocation &rel : isec->relocs())
-            if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) {
-              needTlsSymbol = true;
-              return;
-            }
-      });
-  return needTlsSymbol;
-}
-
-// Check if any input section has a TLS GD PLT relocation. This is used early
-// in the linking process before output sections are populated.
-bool elf::hexagonNeedsTLSSymbolEarly(Ctx &ctx) {
-  for (InputSectionBase *sec : ctx.inputSections) {
-    auto *isec = dyn_cast<InputSection>(sec);
-    if (!isec)
-      continue;
-    for (const Relocation &rel : isec->relocs())
-      if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC)
-        return true;
-  }
-  return false;
-}
-
+// Rebind call x at GDPLT to call __tls_get_addr. The __tls_get_addr symbol and
+// its PLT entry are created during scanRelocations.
 void elf::hexagonTLSSymbolUpdate(Ctx &ctx) {
   Symbol *sym = ctx.symtab->find("__tls_get_addr");
   if (!sym)
     return;
-  // Rebind TLS GD PLT relocations from the TLS symbol to __tls_get_addr.
-  // The PLT entry for __tls_get_addr should already be created by
-  // postScanRelocations since NEEDS_PLT is set on it.
   forEachInputSectionDescription(
       ctx.outputSections, [&](OutputSection *os, InputSectionDescription *isd) {
         for (InputSection *isec : isd->sections)
diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h
index db312e5a35146..dda0013ad4155 100644
--- a/lld/ELF/Relocations.h
+++ b/lld/ELF/Relocations.h
@@ -172,8 +172,6 @@ void postScanRelocations(Ctx &ctx);
 void addGotEntry(Ctx &ctx, Symbol &sym);
 
 void hexagonTLSSymbolUpdate(Ctx &ctx);
-bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
-bool hexagonNeedsTLSSymbolEarly(Ctx &ctx);
 
 bool isAbsolute(const Symbol &sym);
 
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index eccf67c1a480f..5334204e6a40b 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -1920,17 +1920,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
     // a linker-script-defined symbol is absolute.
     scanRelocations<ELFT>(ctx);
     reportUndefinedSymbols(ctx);
-
-    // For Hexagon TLS GD PLT relocations, create __tls_get_addr symbol before
-    // postScanRelocations so that its PLT entry is created at the right time.
-    if (ctx.arg.emachine == EM_HEXAGON && hexagonNeedsTLSSymbolEarly(ctx)) {
-      Symbol *sym =
-          ctx.symtab->addSymbol(Undefined{ctx.internalFile, "__tls_get_addr",
-                                          STB_GLOBAL, STV_DEFAULT, STT_NOTYPE});
-      sym->isPreemptible = true;
-      sym->setFlags(NEEDS_PLT);
-    }
-
     postScanRelocations(ctx);
 
     if (ctx.in.plt && ctx.in.plt->isNeeded())
@@ -2048,9 +2037,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
       sec->addrExpr = [=] { return i->second; };
   }
 
-  // Note: __tls_get_addr is now created earlier (before postScanRelocations)
-  // so that its PLT entry is created at the right time. We just need to add
-  // it to the dynamic symbol table here if it exists.
+  // For Hexagon TLS GD, __tls_get_addr is created during scanRelocations.
+  // Add it to the dynamic symbol table if it exists.
   if (ctx.arg.emachine == EM_HEXAGON) {
     if (Symbol *sym = ctx.symtab->find("__tls_get_addr"))
       ctx.partitions[0].dynSymTab->addSymbol(sym);
diff --git a/lld/test/ELF/hexagon-tls-gd-plt-direct.s b/lld/test/ELF/hexagon-tls-gd-plt-direct.s
index 9d54fcae269b2..d6a9c1b02191c 100644
--- a/lld/test/ELF/hexagon-tls-gd-plt-direct.s
+++ b/lld/test/ELF/hexagon-tls-gd-plt-direct.s
@@ -3,11 +3,9 @@
 # RUN: ld.lld -shared %t.o -o %t.so
 # RUN: llvm-readobj -r %t.so | FileCheck %s
 
-## This test verifies that lld doesn't crash when there's a direct GD_PLT
-## relocation against __tls_get_addr, which can happen when the assembler
-## incorrectly marks __tls_get_addr as STT_TLS due to the @GDPLT suffix.
-## The linker should handle this gracefully by not creating duplicate PLT
-## entries for __tls_get_addr.
+## This test verifies that lld handles the case where there's a direct GD_PLT
+## relocation against __tls_get_addr. Previously this would create duplicate
+## R_HEX_JMP_SLOT relocations for __tls_get_addr. Now only one is created.
 
 # CHECK:      Section ({{.*}}) .rela.dyn {
 # CHECK-NEXT:   R_HEX_DTPMOD_32 foo 0x0
@@ -24,7 +22,6 @@ _start:
   r2 = add(pc, ##_GLOBAL_OFFSET_TABLE_ at PCREL)
   r0 = add(r2, ##foo at GDGOT)
   ## This creates GD_PLT relocations against __tls_get_addr directly
-  ## (not a TLS symbol), which used to cause an assertion failure
   call ##__tls_get_addr at GDPLT
   jumpr r31
 



More information about the llvm-commits mailing list