Skip to content

Commit

Permalink
[ELF] Support mixed TLSDESC and TLS GD
Browse files Browse the repository at this point in the history
We only support both TLSDESC and TLS GD for x86 so this is an x86-specific
problem. If both are used, only one R_X86_64_TLSDESC is produced and TLS GD
accesses will incorrectly reference R_X86_64_TLSDESC. Fix this by introducing
SymbolAux::tlsDescIdx.

Reviewed By: ikudrin

Differential Revision: https://reviews.llvm.org/D116900
  • Loading branch information
MaskRay committed Jan 10, 2022
1 parent 82fb4f4 commit 7f1955d
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 11 deletions.
9 changes: 4 additions & 5 deletions lld/ELF/InputSection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -823,14 +823,13 @@ uint64_t InputSectionBase::getRelocTargetVA(const InputFile *file, RelType type,
case R_SIZE:
return sym.getSize() + a;
case R_TLSDESC:
return in.got->getGlobalDynAddr(sym) + a;
return in.got->getTlsDescAddr(sym) + a;
case R_TLSDESC_PC:
return in.got->getGlobalDynAddr(sym) + a - p;
return in.got->getTlsDescAddr(sym) + a - p;
case R_TLSDESC_GOTPLT:
return in.got->getGlobalDynAddr(sym) + a - in.gotPlt->getVA();
return in.got->getTlsDescAddr(sym) + a - in.gotPlt->getVA();
case R_AARCH64_TLSDESC_PAGE:
return getAArch64Page(in.got->getGlobalDynAddr(sym) + a) -
getAArch64Page(p);
return getAArch64Page(in.got->getTlsDescAddr(sym) + a) - getAArch64Page(p);
case R_TLSGD_GOT:
return in.got->getGlobalDynOffset(sym) + a;
case R_TLSGD_GOTPLT:
Expand Down
7 changes: 3 additions & 4 deletions lld/ELF/Relocations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1609,13 +1609,12 @@ void elf::postScanRelocations() {
bool isLocalInExecutable = !sym.isPreemptible && !config->shared;

if (sym.needsTlsDesc) {
in.got->addDynTlsEntry(sym);
in.got->addTlsDescEntry(sym);
mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
target->tlsDescRel, *in.got, in.got->getGlobalDynOffset(sym), sym,
target->tlsDescRel, *in.got, in.got->getTlsDescOffset(sym), sym,
target->tlsDescRel);
}
if (sym.needsTlsGd && !sym.needsTlsDesc) {
// TODO Support mixed TLSDESC and TLS GD.
if (sym.needsTlsGd) {
in.got->addDynTlsEntry(sym);
uint64_t off = in.got->getGlobalDynOffset(sym);
if (isLocalInExecutable)
Expand Down
4 changes: 4 additions & 0 deletions lld/ELF/Symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct StringRefZ {
struct SymbolAux {
uint32_t gotIdx = -1;
uint32_t pltIdx = -1;
uint32_t tlsDescIdx = -1;
uint32_t tlsGdIdx = -1;
};

Expand Down Expand Up @@ -206,6 +207,9 @@ class Symbol {
uint32_t getPltIdx() const {
return auxIdx == uint32_t(-1) ? uint32_t(-1) : symAux[auxIdx].pltIdx;
}
uint32_t getTlsDescIdx() const {
return auxIdx == uint32_t(-1) ? uint32_t(-1) : symAux[auxIdx].tlsDescIdx;
}
uint32_t getTlsGdIdx() const {
return auxIdx == uint32_t(-1) ? uint32_t(-1) : symAux[auxIdx].tlsGdIdx;
}
Expand Down
15 changes: 15 additions & 0 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,13 @@ void GotSection::addEntry(Symbol &sym) {
symAux.back().gotIdx = numEntries++;
}

bool GotSection::addTlsDescEntry(Symbol &sym) {
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().tlsDescIdx = numEntries;
numEntries += 2;
return true;
}

bool GotSection::addDynTlsEntry(Symbol &sym) {
assert(sym.auxIdx == symAux.size() - 1);
symAux.back().tlsGdIdx = numEntries;
Expand All @@ -672,6 +679,14 @@ bool GotSection::addTlsIndex() {
return true;
}

uint32_t GotSection::getTlsDescOffset(const Symbol &sym) const {
return sym.getTlsDescIdx() * config->wordsize;
}

uint64_t GotSection::getTlsDescAddr(const Symbol &sym) const {
return getVA() + getTlsDescOffset(sym);
}

uint64_t GotSection::getGlobalDynAddr(const Symbol &b) const {
return this->getVA() + b.getTlsGdIdx() * config->wordsize;
}
Expand Down
3 changes: 3 additions & 0 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,11 @@ class GotSection : public SyntheticSection {
void writeTo(uint8_t *buf) override;

void addEntry(Symbol &sym);
bool addTlsDescEntry(Symbol &sym);
bool addDynTlsEntry(Symbol &sym);
bool addTlsIndex();
uint32_t getTlsDescOffset(const Symbol &sym) const;
uint64_t getTlsDescAddr(const Symbol &sym) const;
uint64_t getGlobalDynAddr(const Symbol &b) const;
uint64_t getGlobalDynOffset(const Symbol &b) const;

Expand Down
6 changes: 4 additions & 2 deletions lld/test/ELF/x86-64-tlsdesc-gd-mixed.s
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
# RUN: ld.lld -shared %t.o -o %t.so
# RUN: llvm-readobj -r %t.so | FileCheck %s --check-prefix=RELA

## FIXME Both TLSDESC and DTPMOD64/DTPOFF64 should be present.
## Both TLSDESC and DTPMOD64/DTPOFF64 should be present.
# RELA: .rela.dyn {
# RELA-NEXT: 0x2430 R_X86_64_TLSDESC a 0x0
# RELA-NEXT: 0x[[#%X,ADDR:]] R_X86_64_TLSDESC a 0x0
# RELA-NEXT: 0x[[#ADDR+16]] R_X86_64_DTPMOD64 a 0x0
# RELA-NEXT: 0x[[#ADDR+24]] R_X86_64_DTPOFF64 a 0x0
# RELA-NEXT: }

leaq a@tlsdesc(%rip), %rax
Expand Down

0 comments on commit 7f1955d

Please sign in to comment.