Skip to content

Commit

Permalink
[LLD][ELF][Hexagon] Support GDPLT transforms
Browse files Browse the repository at this point in the history
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
  • Loading branch information
SidManning committed Mar 13, 2020
1 parent bf99053 commit 5a5a075
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 0 deletions.
2 changes: 2 additions & 0 deletions lld/ELF/Arch/Hexagon.cpp
Expand Up @@ -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:
Expand Down Expand Up @@ -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);
Expand Down
38 changes: 38 additions & 0 deletions lld/ELF/Relocations.cpp
Expand Up @@ -1980,6 +1980,44 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
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 &);
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/Relocations.h
Expand Up @@ -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;
Expand Down
13 changes: 13 additions & 0 deletions lld/ELF/Writer.cpp
Expand Up @@ -1592,6 +1592,10 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
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);
Expand Down Expand Up @@ -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.
Expand Down
47 changes: 47 additions & 0 deletions 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@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:]

0 comments on commit 5a5a075

Please sign in to comment.