diff options
-rw-r--r-- | lld/ELF/InputSection.cpp | 8 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 23 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 4 | ||||
-rw-r--r-- | lld/ELF/Target.cpp | 3 | ||||
-rw-r--r-- | lld/ELF/Target.h | 4 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 19 | ||||
-rw-r--r-- | lld/test/elf2/tls-dynamic.s | 20 |
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 |