Hexagon ABI specifies that call x@gdplt is transformed to call __tls_get_addr.
Example:
call x@gdplt
is changed to
call __tls_get_addr
When x is an external tls variable.
Differential Revision: https://reviews.llvm.org/D74443
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:
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);
return addressesChanged;
}
+// The following aid in the conversion of call x@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 &);
template <class ELFT> void reportUndefinedSymbols();
+void hexagonTLSSymbolUpdate(ArrayRef<OutputSection *> outputSections);
+bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
+
class ThunkSection;
class Thunk;
struct InputSectionDescription;
ARMErr657417Patcher a32p;
script->assignAddresses();
+ // Converts call x@GDPLT to call __tls_get_addr
+ if (config->emachine == EM_HEXAGON)
+ hexagonTLSSymbolUpdate(outputSections);
+
int assignPasses = 0;
for (;;) {
bool changed = target->needsThunks && tc.createThunks(outputSections);
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.
--- /dev/null
+# 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@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:]