[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