[lld][Hexagon] Fix TLS GD PLT to only create PLT entry for __tls_get_addr (#180297)
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. --------- Co-authored-by: Fangrui Song <i@maskray.me>
This commit is contained in:
parent
3481129c49
commit
8f4f515898
@ -9,6 +9,7 @@
|
||||
#include "InputFiles.h"
|
||||
#include "OutputSections.h"
|
||||
#include "RelocScan.h"
|
||||
#include "SymbolTable.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
@ -43,6 +44,7 @@ public:
|
||||
void scanSection(InputSectionBase &sec) override {
|
||||
elf::scanSection1<Hexagon, ELF32LE>(*this, sec);
|
||||
}
|
||||
void finalizeRelocScan() override;
|
||||
bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
||||
uint64_t branchAddr, const Symbol &s,
|
||||
int64_t a) const override;
|
||||
@ -182,7 +184,11 @@ void Hexagon::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
|
||||
case R_HEX_GD_PLT_B22_PCREL:
|
||||
case R_HEX_GD_PLT_B22_PCREL_X:
|
||||
case R_HEX_GD_PLT_B32_PCREL_X:
|
||||
sym.setFlags(NEEDS_PLT);
|
||||
// GD PLT: call foo@GDPLT becomes call __tls_get_addr.
|
||||
// Record R_PLT_PC on the TLS symbol; finalizeRelocScan (called
|
||||
// single-threaded after scanning) will create __tls_get_addr and
|
||||
// rebind these relocations. We cannot access the symbol table here
|
||||
// because scanSectionImpl runs in parallel.
|
||||
sec.addReloc({R_PLT_PC, type, offset, addend, &sym});
|
||||
continue;
|
||||
|
||||
@ -664,4 +670,43 @@ void elf::mergeHexagonAttributesSections(Ctx &ctx) {
|
||||
mergeAttributesSection(ctx, sections));
|
||||
}
|
||||
|
||||
static bool isGDPLT(RelType type) {
|
||||
switch (type) {
|
||||
case R_HEX_GD_PLT_B22_PCREL:
|
||||
case R_HEX_GD_PLT_B22_PCREL_X:
|
||||
case R_HEX_GD_PLT_B32_PCREL_X:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Hexagon::finalizeRelocScan() {
|
||||
Symbol *tga = nullptr;
|
||||
|
||||
// Scan for R_HEX_GD_PLT_* relocations (recorded as R_PLT_PC by
|
||||
// scanSectionImpl) and rebind them to __tls_get_addr.
|
||||
for (ELFFileBase *f : ctx.objectFiles) {
|
||||
for (InputSectionBase *s : f->getSections()) {
|
||||
auto *isec = dyn_cast_or_null<InputSection>(s);
|
||||
if (!isec || !isec->isLive())
|
||||
continue;
|
||||
for (Relocation &rel : isec->relocs()) {
|
||||
if (rel.expr != R_PLT_PC || !isGDPLT(rel.type))
|
||||
continue;
|
||||
if (!tga) {
|
||||
tga = ctx.symtab->addSymbol(Undefined{ctx.internalFile,
|
||||
"__tls_get_addr", STB_GLOBAL,
|
||||
STV_DEFAULT, STT_FUNC});
|
||||
tga->isUsedInRegularObj = true;
|
||||
tga->used = true;
|
||||
tga->isPreemptible = true;
|
||||
tga->setFlags(NEEDS_PLT);
|
||||
}
|
||||
rel.sym = tga;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void elf::setHexagonTargetInfo(Ctx &ctx) { ctx.target.reset(new Hexagon(ctx)); }
|
||||
|
||||
@ -1406,6 +1406,8 @@ void elf::postScanRelocations(Ctx &ctx) {
|
||||
}
|
||||
};
|
||||
|
||||
ctx.target->finalizeRelocScan();
|
||||
|
||||
GotSection *got = ctx.in.got.get();
|
||||
if (ctx.needsTlsLd.load(std::memory_order_relaxed) && got->addTlsIndex()) {
|
||||
if (ctx.arg.shared)
|
||||
@ -1991,46 +1993,6 @@ bool ThunkCreator::createThunks(uint32_t pass,
|
||||
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 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;
|
||||
}
|
||||
|
||||
void elf::hexagonTLSSymbolUpdate(Ctx &ctx) {
|
||||
Symbol *sym = ctx.symtab->find("__tls_get_addr");
|
||||
if (!sym)
|
||||
return;
|
||||
bool needEntry = true;
|
||||
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;
|
||||
}
|
||||
rel.sym = sym;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static bool matchesRefTo(const NoCrossRefCommand &cmd, StringRef osec) {
|
||||
if (cmd.toFirst)
|
||||
return cmd.outputSections[0] == osec;
|
||||
|
||||
@ -160,9 +160,6 @@ bool maybeReportUndefined(Ctx &, Undefined &sym, InputSectionBase &sec,
|
||||
void postScanRelocations(Ctx &ctx);
|
||||
void addGotEntry(Ctx &ctx, Symbol &sym);
|
||||
|
||||
void hexagonTLSSymbolUpdate(Ctx &ctx);
|
||||
bool hexagonNeedsTLSSymbol(ArrayRef<OutputSection *> outputSections);
|
||||
|
||||
bool isAbsolute(const Symbol &sym);
|
||||
|
||||
class ThunkSection;
|
||||
|
||||
@ -99,6 +99,12 @@ public:
|
||||
template <class ELFT, class RelTy>
|
||||
void scanSectionImpl(InputSectionBase &, Relocs<RelTy>);
|
||||
|
||||
// Called after parallel relocation scanning is complete but before
|
||||
// postScanRelocations processes symbol flags. Targets may override this to
|
||||
// perform single-threaded fixups that cannot run during parallel scanning
|
||||
// (e.g. symbol table modifications).
|
||||
virtual void finalizeRelocScan() {}
|
||||
|
||||
virtual void relocate(uint8_t *loc, const Relocation &rel,
|
||||
uint64_t val) const = 0;
|
||||
void relocateNoSym(uint8_t *loc, RelType type, uint64_t val) const {
|
||||
|
||||
@ -1538,10 +1538,6 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
|
||||
};
|
||||
finalizeOrderDependentContent();
|
||||
|
||||
// Converts call x@GDPLT to call __tls_get_addr
|
||||
if (ctx.arg.emachine == EM_HEXAGON)
|
||||
hexagonTLSSymbolUpdate(ctx);
|
||||
|
||||
if (ctx.arg.randomizeSectionPadding)
|
||||
randomizeSectionPadding(ctx);
|
||||
|
||||
@ -2042,17 +2038,6 @@ 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);
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
@ -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@plt> }
|
||||
# CHECK-NEXT: { call 0x410310 <__tls_get_addr@plt> }
|
||||
# CHECK-NEXT: { immext(#0xfffeffc0)
|
||||
# CHECK-NEXT: r0 = add(r2,##-0x10010) }
|
||||
# CHECK-NEXT: { call 0x410360 <__tls_get_addr@plt> }
|
||||
# CHECK-NEXT: { call 0x410310 <__tls_get_addr@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@plt> }
|
||||
# CHECK-NEXT: { call 0x410310 <__tls_get_addr@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@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@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@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 }
|
||||
|
||||
@ -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: }
|
||||
|
||||
|
||||
31
lld/test/ELF/hexagon-tls-gd-plt-direct.s
Normal file
31
lld/test/ELF/hexagon-tls-gd-plt-direct.s
Normal file
@ -0,0 +1,31 @@
|
||||
# REQUIRES: hexagon
|
||||
# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t.o
|
||||
# RUN: ld.lld -shared %t.o --gc-sections -o %t.so
|
||||
# RUN: llvm-readobj -r %t.so | FileCheck %s
|
||||
|
||||
## This test verifies that a GD_PLT relocation on a TLS variable does not
|
||||
## create a spurious R_HEX_JMP_SLOT for that variable — only
|
||||
## __tls_get_addr should get a PLT entry.
|
||||
|
||||
# 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_@PCREL)
|
||||
r0 = add(r2, ##foo@GDGOT)
|
||||
call foo@GDPLT
|
||||
jumpr r31
|
||||
|
||||
.section .tdata,"awT",@progbits
|
||||
.globl foo
|
||||
.type foo, @object
|
||||
foo:
|
||||
.word 0x11111111
|
||||
@ -18,25 +18,24 @@
|
||||
_start:
|
||||
.ifdef GDPLT
|
||||
call x@gdplt
|
||||
# CHECK_GDPLT: 101ec: { call 0x10220 <__tls_get_addr@plt> }
|
||||
# CHECK_GDPLT: 101e0: { call 0x10210 <__tls_get_addr@plt> }
|
||||
.else
|
||||
call x
|
||||
# CHECK: 101b8: { call 0x101e0 <x@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:]
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user