[ELF][MIPS] Fix initialization of TLS-related GOT entries
This patch allows static linking of TLS code. To do that it fixes
GOT entries initialization.
If TLS-related GOT entry created for a preemptible symbol i.e. has
a corresponding dynamic relocation, leave the entry initialized by zero.
Write down adjusted TLS symbol's values otherwise. For the adjustments
calculation use offsets for thread-local storage.
https://www.linux-mips.org/wiki/NPTL
llvm-svn: 280914
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index f245120..278e5c5 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -261,7 +261,7 @@
this->Header.sh_size = EntriesNum * sizeof(uintX_t);
}
-template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) {
+template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *Buf) {
// Set the MSB of the second GOT slot. This is not required by any
// MIPS ABI documentation, though.
//
@@ -293,11 +293,38 @@
};
std::for_each(std::begin(MipsLocal), std::end(MipsLocal), AddEntry);
std::for_each(std::begin(MipsGlobal), std::end(MipsGlobal), AddEntry);
+ // Initialize TLS-related GOT entries. If the entry has a corresponding
+ // dynamic relocations, leave it initialized by zero. Write down adjusted
+ // TLS symbol's values otherwise. To calculate the adjustments use offsets
+ // for thread-local storage.
+ // https://www.linux-mips.org/wiki/NPTL
+ if (TlsIndexOff != -1U && !Config->Pic)
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Buf + TlsIndexOff,
+ 1);
+ for (const SymbolBody *B : Entries) {
+ if (!B || B->isPreemptible())
+ continue;
+ uintX_t VA = B->getVA<ELFT>();
+ if (B->GotIndex != -1U) {
+ uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry,
+ VA - 0x7000);
+ }
+ if (B->GlobalDynIndex != -1U) {
+ uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, 1);
+ Entry += sizeof(uintX_t);
+ write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry,
+ VA - 0x8000);
+ }
+ }
}
template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) {
- if (Config->EMachine == EM_MIPS)
+ if (Config->EMachine == EM_MIPS) {
writeMipsGot(Buf);
+ return;
+ }
for (const SymbolBody *B : Entries) {
uint8_t *Entry = Buf;
Buf += sizeof(uintX_t);