summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/ELF/InputSection.cpp8
-rw-r--r--lld/ELF/OutputSections.cpp23
-rw-r--r--lld/ELF/OutputSections.h4
-rw-r--r--lld/ELF/Target.cpp3
-rw-r--r--lld/ELF/Target.h4
-rw-r--r--lld/ELF/Writer.cpp19
-rw-r--r--lld/test/elf2/tls-dynamic.s20
7 files changed, 72 insertions, 9 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 5916ad7f558..afb373decc6 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -126,6 +126,14 @@ void InputSectionBase<ELFT>::relocate(
}
SymbolBody &Body = *File->getSymbolBody(SymIndex)->repl();
+
+ if (Type == Target->getTlsGlobalDynamicReloc()) {
+ Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
+ Out<ELFT>::Got->getEntryAddr(Body) +
+ getAddend<ELFT>(RI));
+ continue;
+ }
+
uintX_t SymVA = getSymVA<ELFT>(Body);
if (Target->relocNeedsPlt(Type, Body)) {
SymVA = Out<ELFT>::Plt->getEntryAddr(Body);
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 1c8311c9864..9def8708595 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -80,6 +80,9 @@ GotSection<ELFT>::GotSection()
template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
Sym->GotIndex = Target->getGotHeaderEntriesNum() + Entries.size();
Entries.push_back(Sym);
+ // Global Dynamic TLS entries take two GOT slots.
+ if (Sym->isTLS())
+ Entries.push_back(nullptr);
}
template <class ELFT> uint32_t GotSection<ELFT>::addLocalModuleTlsIndex() {
@@ -187,8 +190,13 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
auto *P = reinterpret_cast<Elf_Rel *>(Buf);
Buf += EntrySize;
- InputSectionBase<ELFT> &C = Rel.C;
- const Elf_Rel &RI = Rel.RI;
+ // Skip placeholder for global dynamic TLS relocation pair. It was already
+ // handled by the previous relocation.
+ if (!Rel.C || !Rel.RI)
+ continue;
+
+ InputSectionBase<ELFT> &C = *Rel.C;
+ const Elf_Rel &RI = *Rel.RI;
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
const ObjectFile<ELFT> &File = *C.getFile();
SymbolBody *Body = File.getSymbolBody(SymIndex);
@@ -205,6 +213,17 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
continue;
}
+ if (Body && Type == Target->getTlsGlobalDynamicReloc()) {
+ P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
+ Target->getTlsModuleIndexReloc(), Config->Mips64EL);
+ P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body);
+ auto *PNext = reinterpret_cast<Elf_Rel *>(Buf);
+ PNext->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
+ Target->getTlsOffsetReloc(), Config->Mips64EL);
+ PNext->r_offset = Out<ELFT>::Got->getEntryAddr(*Body) + sizeof(uintX_t);
+ 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 d4846bca0ea..83136b01a0e 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -170,8 +170,8 @@ private:
template <class ELFT> struct DynamicReloc {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- InputSectionBase<ELFT> &C;
- const Elf_Rel &RI;
+ InputSectionBase<ELFT> *C;
+ const Elf_Rel *RI;
};
template <class ELFT>
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 5fae919c835..34e6c857e0c 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -216,7 +216,9 @@ X86_64TargetInfo::X86_64TargetInfo() {
PltReloc = R_X86_64_JUMP_SLOT;
RelativeReloc = R_X86_64_RELATIVE;
TlsLocalDynamicReloc = R_X86_64_TLSLD;
+ TlsGlobalDynamicReloc = R_X86_64_TLSGD;
TlsModuleIndexReloc = R_X86_64_DTPMOD64;
+ TlsOffsetReloc = R_X86_64_DTPOFF64;
LazyRelocations = true;
PltEntrySize = 16;
PltZeroEntrySize = 16;
@@ -335,6 +337,7 @@ void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
case R_X86_64_GOTPCREL:
case R_X86_64_PLT32:
case R_X86_64_TLSLD:
+ case R_X86_64_TLSGD:
write32le(Loc, SA - P);
break;
case R_X86_64_64:
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 43c4d49e0d4..55ea6146b15 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -30,7 +30,9 @@ public:
unsigned getGotRefReloc() const { return GotRefReloc; }
unsigned getRelativeReloc() const { return RelativeReloc; }
unsigned getTlsLocalDynamicReloc() const { return TlsLocalDynamicReloc; }
+ unsigned getTlsGlobalDynamicReloc() const { return TlsGlobalDynamicReloc; }
unsigned getTlsModuleIndexReloc() const { return TlsModuleIndexReloc; }
+ unsigned getTlsOffsetReloc() const { return TlsOffsetReloc; }
unsigned getPltZeroEntrySize() const { return PltZeroEntrySize; }
unsigned getPltEntrySize() const { return PltEntrySize; }
bool supportsLazyRelocations() const { return LazyRelocations; }
@@ -70,7 +72,9 @@ protected:
unsigned PltReloc;
unsigned RelativeReloc;
unsigned TlsLocalDynamicReloc = 0;
+ unsigned TlsGlobalDynamicReloc = 0;
unsigned TlsModuleIndexReloc;
+ unsigned TlsOffsetReloc;
unsigned PltEntrySize = 8;
unsigned PltZeroEntrySize = 0;
unsigned GotHeaderEntriesNum = 0;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 7d0f49ba2ad..4772bec3a6d 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -203,7 +203,7 @@ void Writer<ELFT>::scanRelocs(
if (Out<ELFT>::LocalModuleTlsIndexOffset == uint32_t(-1)) {
Out<ELFT>::LocalModuleTlsIndexOffset =
Out<ELFT>::Got->addLocalModuleTlsIndex();
- Out<ELFT>::RelaDyn->addReloc({C, RI});
+ Out<ELFT>::RelaDyn->addReloc({&C, &RI});
}
continue;
}
@@ -215,6 +215,19 @@ void Writer<ELFT>::scanRelocs(
if (Body)
Body = Body->repl();
+
+ if (Body && Body->isTLS()) {
+ if (Type != Target->getTlsGlobalDynamicReloc())
+ continue;
+ if (Body->isInGot())
+ continue;
+ Out<ELFT>::Got->addEntry(Body);
+ Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ Out<ELFT>::RelaDyn->addReloc({nullptr, nullptr});
+ Body->setUsedInDynamicReloc();
+ continue;
+ }
+
bool NeedsGot = false;
bool NeedsPlt = false;
if (Body) {
@@ -257,9 +270,9 @@ void Writer<ELFT>::scanRelocs(
if (CBP)
Body->setUsedInDynamicReloc();
if (NeedsPlt && Target->supportsLazyRelocations())
- Out<ELFT>::RelaPlt->addReloc({C, RI});
+ Out<ELFT>::RelaPlt->addReloc({&C, &RI});
else
- Out<ELFT>::RelaDyn->addReloc({C, RI});
+ Out<ELFT>::RelaDyn->addReloc({&C, &RI});
}
}
diff --git a/lld/test/elf2/tls-dynamic.s b/lld/test/elf2/tls-dynamic.s
index 36a6129f923..03a52c4f24b 100644
--- a/lld/test/elf2/tls-dynamic.s
+++ b/lld/test/elf2/tls-dynamic.s
@@ -11,6 +11,10 @@
leaq a@dtpoff(%rax), %rcx
leaq b@dtpoff(%rax), %rcx
.long b@dtpoff, 0
+ leaq c@tlsgd(%rip), %rdi
+ rex64
+ callq __tls_get_addr@PLT
+ leaq c@dtpoff(%rax), %rcx
.global a
.hidden a
@@ -23,8 +27,14 @@ a:
.align 4
b:
.long 0
+
+ .global c
+ .section .tbss,"awT",@nobits
+ .align 4
+c:
+ .long 0
-// Get the address of the got, and check that it has two entries.
+// Get the address of the got, and check that it has 4 entries.
// CHECK: Sections [
// CHECK: Name: .got
@@ -35,15 +45,18 @@ b:
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x20D0
// CHECK-NEXT: Offset:
-// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Size: 32
// CHECK: Relocations [
// CHECK: Section ({{.+}}) .rela.dyn {
// CHECK-NEXT: 0x20D0 R_X86_64_DTPMOD64 - 0x0
+// CHECK-NEXT: 0x20E0 R_X86_64_DTPMOD64 c 0x0
+// CHECK-NEXT: 0x20E8 R_X86_64_DTPOFF64 c 0x0
// CHECK-NEXT: }
// 4297 = (0x20D0 + -4) - (0x1000 + 3) // PC relative offset to got entry.
// 4285 = (0x20D0 + -4) - (0x100c + 3) // PC relative offset to got entry.
+// 4267 = (0x20E0 + -4) - (0x102e + 3) // PC relative offset to got entry.
// DIS: Disassembly of section .text:
// DIS-NEXT: .text:
@@ -57,3 +70,6 @@ b:
// DIS-NEXT: 1028: 00 00
// DIS-NEXT: 102a: 00 00
// DIS-NEXT: 102c: 00 00
+// DIS-NEXT: 102e: {{.+}} leaq 4267(%rip), %rdi
+// DIS-NEXT: 1035: {{.+}} callq
+// DIS-NEXT: 103b: {{.+}} leaq 8(%rax), %rcx
OpenPOWER on IntegriCloud