summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp15
-rw-r--r--lld/ELF/OutputSections.cpp17
-rw-r--r--lld/ELF/OutputSections.h3
-rw-r--r--lld/ELF/Target.cpp3
-rw-r--r--lld/ELF/Target.h4
-rw-r--r--lld/ELF/Writer.cpp9
-rw-r--r--lld/test/elf2/tls-dynamic.s48
7 files changed, 96 insertions, 3 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 1e5f37b86f9..9b9e99c67d3 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -90,14 +90,23 @@ void InputSection<ELFT>::relocate(
for (const RelType &RI : Rels) {
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
uint32_t Type = RI.getType(Config->Mips64EL);
+ uint8_t *BufLoc = Buf + RI.r_offset;
+ uintX_t AddrLoc = BaseAddr + RI.r_offset;
+
+ if (Type == Target->getTlsLocalDynamicReloc()) {
+ Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
+ Out<ELFT>::Got->getVA() +
+ Out<ELFT>::LocalModuleTlsIndexOffset +
+ getAddend<ELFT>(RI));
+ continue;
+ }
// Handle relocations for local symbols -- they never get
// resolved so we don't allocate a SymbolBody.
const Elf_Shdr *SymTab = File.getSymbolTable();
if (SymIndex < SymTab->sh_info) {
uintX_t SymVA = getLocalRelTarget(File, RI);
- Target->relocateOne(Buf + RI.r_offset, BufEnd, Type,
- BaseAddr + RI.r_offset, SymVA);
+ Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA);
continue;
}
@@ -116,7 +125,7 @@ void InputSection<ELFT>::relocate(
isa<SharedSymbol<ELFT>>(Body)) {
continue;
}
- Target->relocateOne(Buf + RI.r_offset, BufEnd, Type, BaseAddr + RI.r_offset,
+ Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
SymVA + getAddend<ELFT>(RI));
}
}
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 0a6c33c1d02..c6b74fffc46 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -82,6 +82,12 @@ template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
Entries.push_back(Sym);
}
+template <class ELFT> uint32_t GotSection<ELFT>::addLocalModuleTlsIndex() {
+ Entries.push_back(nullptr);
+ Entries.push_back(nullptr);
+ return (Entries.size() - 2) * sizeof(uintX_t);
+}
+
template <class ELFT>
typename GotSection<ELFT>::uintX_t
GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
@@ -99,6 +105,8 @@ template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
for (const SymbolBody *B : Entries) {
uint8_t *Entry = Buf;
Buf += sizeof(uintX_t);
+ if (!B)
+ continue;
// MIPS has special rules to fill up GOT entries.
// See "Global Offset Table" in Chapter 5 in the following document
// for detailed description:
@@ -177,6 +185,15 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
Body = Body->repl();
uint32_t Type = RI.getType(Config->Mips64EL);
+
+ if (Type == Target->getTlsLocalDynamicReloc()) {
+ P->setSymbolAndType(0, Target->getTlsModuleIndexReloc(),
+ Config->Mips64EL);
+ P->r_offset =
+ Out<ELFT>::Got->getVA() + Out<ELFT>::LocalModuleTlsIndexOffset;
+ continue;
+ }
+
bool NeedsCopy = Body && Target->relocNeedsCopy(Type, *Body);
bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body);
bool CanBePreempted = canBePreempted(Body, NeedsGot);
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 1714f51990c..1afd8bf8631 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -116,6 +116,7 @@ public:
void finalize() override;
void writeTo(uint8_t *Buf) override;
void addEntry(SymbolBody *Sym);
+ uint32_t addLocalModuleTlsIndex();
bool empty() const { return Entries.empty(); }
uintX_t getEntryAddr(const SymbolBody &B) const;
@@ -371,6 +372,7 @@ template <class ELFT> struct Out {
static SymbolTableSection<ELFT> *DynSymTab;
static SymbolTableSection<ELFT> *SymTab;
static Elf_Phdr *TlsPhdr;
+ static uint32_t LocalModuleTlsIndexOffset;
};
template <class ELFT> DynamicSection<ELFT> *Out<ELFT>::Dynamic;
@@ -391,6 +393,7 @@ template <class ELFT> StringTableSection<ELFT> *Out<ELFT>::StrTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::DynSymTab;
template <class ELFT> SymbolTableSection<ELFT> *Out<ELFT>::SymTab;
template <class ELFT> typename Out<ELFT>::Elf_Phdr *Out<ELFT>::TlsPhdr;
+template <class ELFT> uint32_t Out<ELFT>::LocalModuleTlsIndexOffset = -1;
} // namespace elf2
} // namespace lld
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index f01c7299ec8..34e567052d5 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -215,6 +215,8 @@ X86_64TargetInfo::X86_64TargetInfo() {
GotRefReloc = R_X86_64_PC32;
PltReloc = R_X86_64_JUMP_SLOT;
RelativeReloc = R_X86_64_RELATIVE;
+ TlsLocalDynamicReloc = R_X86_64_TLSLD;
+ TlsModuleIndexReloc = R_X86_64_DTPMOD64;
LazyRelocations = true;
PltEntrySize = 16;
PltZeroEntrySize = 16;
@@ -330,6 +332,7 @@ void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
case R_X86_64_PC32:
case R_X86_64_GOTPCREL:
case R_X86_64_PLT32:
+ case R_X86_64_TLSLD:
write32le(Loc, SA - P);
break;
case R_X86_64_64:
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 71ef7eb8584..43c4d49e0d4 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -29,6 +29,8 @@ public:
unsigned getPltReloc() const { return PltReloc; }
unsigned getGotRefReloc() const { return GotRefReloc; }
unsigned getRelativeReloc() const { return RelativeReloc; }
+ unsigned getTlsLocalDynamicReloc() const { return TlsLocalDynamicReloc; }
+ unsigned getTlsModuleIndexReloc() const { return TlsModuleIndexReloc; }
unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; }
unsigned getPltEntrySize() const { return PltEntrySize; }
bool supportsLazyRelocations() const { return LazyRelocations; }
@@ -67,6 +69,8 @@ protected:
unsigned GotReloc;
unsigned PltReloc;
unsigned RelativeReloc;
+ unsigned TlsLocalDynamicReloc = 0;
+ unsigned TlsModuleIndexReloc;
unsigned PltEntrySize = 8;
unsigned PltZeroEntrySize = 0;
unsigned GotHeaderEntriesNum = 0;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 5bed591ab9e..8739a33325c 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -190,6 +190,15 @@ void Writer<ELFT>::scanRelocs(
SymbolBody *Body = File.getSymbolBody(SymIndex);
uint32_t Type = RI.getType(Config->Mips64EL);
+ if (Type == Target->getTlsLocalDynamicReloc()) {
+ if (Out<ELFT>::LocalModuleTlsIndexOffset == uint32_t(-1)) {
+ Out<ELFT>::LocalModuleTlsIndexOffset =
+ Out<ELFT>::Got->addLocalModuleTlsIndex();
+ Out<ELFT>::RelaDyn->addReloc({C, RI});
+ }
+ continue;
+ }
+
// Set "used" bit for --as-needed.
if (Body && Body->isUndefined() && !Body->isWeak())
if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body->repl()))
diff --git a/lld/test/elf2/tls-dynamic.s b/lld/test/elf2/tls-dynamic.s
new file mode 100644
index 00000000000..4cadfc69aa9
--- /dev/null
+++ b/lld/test/elf2/tls-dynamic.s
@@ -0,0 +1,48 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
+// RUN: ld.lld2 -shared %t -o %tout
+// RUN: llvm-readobj -sections -relocations %tout | FileCheck %s
+// RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DIS
+
+ leaq a@tlsld(%rip), %rdi
+ callq __tls_get_addr@PLT
+ leaq b@tlsld(%rip), %rdi
+ callq __tls_get_addr@PLT
+
+ .global a
+ .section .tbss,"awT",@nobits
+ .align 4
+a:
+ .long 0
+
+ .global b
+ .section .tbss,"awT",@nobits
+ .align 4
+b:
+ .long 0
+
+// Get the address of the got, and check that it has two entries.
+
+// CHECK: Sections [
+// CHECK: Name: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x20D0
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+
+// CHECK: Relocations [
+// CHECK: Section ({{.+}}) .rela.dyn {
+// CHECK-NEXT: 0x20D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: }
+
+// 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry.
+
+// DIS: Disassembly of section .text:
+// DIS-NEXT: .text:
+// DIS-NEXT: 1000: {{.+}} leaq 4297(%rip), %rdi
+// DIS-NEXT: 1007: {{.+}} callq
+// DIS-NEXT: 100c: {{.+}} leaq 4285(%rip), %rdi
OpenPOWER on IntegriCloud