diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -823,14 +823,13 @@ 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: diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1609,13 +1609,12 @@ 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) diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -61,6 +61,7 @@ struct SymbolAux { uint32_t gotIdx = -1; uint32_t pltIdx = -1; + uint32_t tlsDescIdx = -1; uint32_t tlsGdIdx = -1; }; @@ -206,6 +207,9 @@ 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; } diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -129,8 +129,11 @@ 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; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -654,6 +654,13 @@ 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; @@ -672,6 +679,14 @@ 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; } diff --git a/lld/test/ELF/x86-64-tlsdesc-gd-mixed.s b/lld/test/ELF/x86-64-tlsdesc-gd-mixed.s --- a/lld/test/ELF/x86-64-tlsdesc-gd-mixed.s +++ b/lld/test/ELF/x86-64-tlsdesc-gd-mixed.s @@ -5,7 +5,9 @@ ## FIXME 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