Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -219,6 +219,8 @@ // Write MIPS-specific parts of the GOT. void writeMipsGot(uint8_t *Buf); + // Write ARM-specific parts of the GOT. + void writeARMGot(uint8_t *Buf); }; template Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -381,11 +381,39 @@ } } +template void GotSection::writeARMGot(uint8_t *Buf) { + if (TlsIndexOff != -1U && !Config->Shared) + writeUint(Buf + TlsIndexOff, 1); + for (const SymbolBody *B : Entries) { + if (!B || B->isPreemptible()) + // The dynamic linker will take care of preemptible entries + continue; + uintX_t VA = B->getVA(); + if (B->GotIndex != -1U) { + if (B->IsTlsGotRel) + VA += alignTo(Target->TcbSize, Out::TlsPhdr->p_align); + uint8_t *Entry = Buf + B->GotIndex * sizeof(uintX_t); + writeUint(Entry, VA); + } + if (B->GlobalDynIndex != -1U) { + uint8_t *Entry = Buf + B->GlobalDynIndex * sizeof(uintX_t); + if (!Config->Shared) + writeUint(Entry, 1); + Entry += sizeof(uintX_t); + writeUint(Entry, VA); + } + } +} + template void GotSection::writeTo(uint8_t *Buf) { if (Config->EMachine == EM_MIPS) { writeMipsGot(Buf); return; } + if (Config->EMachine == EM_ARM) { + writeARMGot(Buf); + return; + } for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ ELF/Relocations.cpp @@ -89,10 +89,6 @@ // support any relaxations for TLS relocations so by factoring out ARM and MIPS // handling in to the separate function we can simplify the code and do not // pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements. -// FIXME: The ARM implementation always adds the module index dynamic -// relocation even for non-preemptible symbols in applications. For static -// linking support we must either resolve the module index relocation at static -// link time, or hard code the module index (1) for the application in the GOT. template static unsigned handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, @@ -101,7 +97,8 @@ RelExpr Expr) { if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { if (Out::Got->addTlsIndex() && - (Config->Pic || Config->EMachine == EM_ARM)) + ((Config->EMachine == EM_MIPS && Config->Pic) || + (Config->EMachine == EM_ARM && Config->Shared))) Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, Out::Got->getTlsIndexOff(), false, nullptr, 0}); @@ -111,7 +108,8 @@ typedef typename ELFT::uint uintX_t; if (Target->isTlsGlobalDynamicRel(Type)) { if (Out::Got->addDynTlsEntry(Body) && - (Body.isPreemptible() || Config->EMachine == EM_ARM)) { + (Body.isPreemptible() || + (Config->EMachine == EM_ARM && Config->Shared))) { uintX_t Off = Out::Got->getGlobalDynOffset(Body); Out::RelaDyn->addReloc( {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); @@ -757,6 +755,8 @@ continue; Out::Got->addEntry(Body); + if (Body.isTls()) + Body.IsTlsGotRel = true; if (Preemptible || (Config->Pic && !isAbsolute(Body))) { uint32_t DynType; if (Body.isTls()) Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -124,6 +124,9 @@ // True if this symbol is referenced by 32-bit GOT relocations. unsigned Is32BitMipsGot : 1; + // True if this symbol is referenced by TlsGotRel relocations. + unsigned IsTlsGotRel : 1; + // The following fields have the same meaning as the ELF symbol attributes. uint8_t Type; // symbol type uint8_t StOther; // st_other field value Index: test/ELF/arm-tls-norelax-gd-le.s =================================================================== --- test/ELF/arm-tls-norelax-gd-le.s +++ test/ELF/arm-tls-norelax-gd-le.s @@ -2,7 +2,7 @@ // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld %t1.so %t.o -o %t -// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s +// RUN: llvm-objdump -s %t | FileCheck %s // REQUIRES: arm // This tls global-dynamic sequence is with respect to a non-preemptible @@ -31,7 +31,7 @@ .space 4 .type x, %object -// CHECK: Dynamic Relocations { -// CHECK-NEXT: 0x12078 R_ARM_TLS_DTPMOD32 -// CHECK-NEXT: 0x1300C R_ARM_JUMP_SLOT __tls_get_addr +// CHECK: Contents of section .got: +// Module index is always 1 for executable +// CHECK-NEXT: 12060 01000000 00000000 Index: test/ELF/arm-tls-norelax-ie-le.s =================================================================== --- test/ELF/arm-tls-norelax-ie-le.s +++ test/ELF/arm-tls-norelax-ie-le.s @@ -2,7 +2,7 @@ // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld %t1.so %t.o -o %t -// RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t +// RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t | FileCheck %s // REQUIRES: arm // This tls Initial Exec sequence is with respect to a non-preemptible symbol @@ -37,5 +37,5 @@ .type x2, %object // CHECK: Contents of section .got -// x1 at offset 0 from TP, x2 at offset 4 from TP -// 12064 00000000 04000000 +// x1 at offset 8 from TP, x2 at offset c from TP. Offsets include TCB size of 8 +// CHECK-NEXT: 12064 08000000 0c000000 Index: test/ELF/arm-tls-norelax-ld-le.s =================================================================== --- test/ELF/arm-tls-norelax-ld-le.s +++ test/ELF/arm-tls-norelax-ld-le.s @@ -2,7 +2,7 @@ // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld %t1.so %t.o -o %t -// RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s +// RUN: llvm-objdump -s %t | FileCheck %s // REQUIRES: arm .global __tls_get_addr @@ -31,6 +31,5 @@ x: .word 10 -// CHECK: Dynamic Relocations { -// CHECK-NEXT: 0x1207C R_ARM_TLS_DTPMOD32 - 0x0 -// CHECK-NEXT: 0x1300C R_ARM_JUMP_SLOT __tls_get_addr 0x0 +// CHECK: Contents of section .got: +// CHECK-NEXT: 12064 01000000 00000000