Index: lld/trunk/ELF/Arch/ARM.cpp =================================================================== --- lld/trunk/ELF/Arch/ARM.cpp +++ lld/trunk/ELF/Arch/ARM.cpp @@ -395,9 +395,6 @@ case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; - case R_ARM_TLS_DTPMOD32: - write32le(Loc, 1); - break; case R_ARM_PREL31: checkInt(Loc, Val, 31, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -147,63 +147,12 @@ return 0; } -// This function is similar to the `handleMipsTlsRelocation`. ARM also does not -// support any relaxations for TLS relocations. ARM is logically similar to Mips -// in how it handles TLS, but Mips uses its own custom GOT which handles some -// of the cases that ARM uses GOT relocations for. -// -// We look for TLS global dynamic and local dynamic relocations, these may -// require the generation of a pair of GOT entries that have associated -// dynamic relocations. When the results of the dynamic relocations can be -// resolved at static link time we do so. This is necessary for static linking -// as there will be no dynamic loader to resolve them at load-time. -// -// The pair of GOT entries created are of the form -// GOT[e0] Module Index (Used to find pointer to TLS block at run-time) -// GOT[e1] Offset of symbol in TLS block -static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, - InputSectionBase &C, uint64_t Offset, - int64_t Addend, RelExpr Expr) { - // The Dynamic TLS Module Index Relocation for a symbol defined in an - // executable is always 1. If the target Symbol is not preemptible then - // we know the offset into the TLS block at static link time. - bool NeedDynId = Sym.IsPreemptible || Config->Shared; - bool NeedDynOff = Sym.IsPreemptible; - - auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { - if (Dyn) - Main->RelaDyn->addReloc(Type, In.Got, Off, Dest); - else - In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); - }; - - // Local Dynamic is for access to module local TLS variables, while still - // being suitable for being dynamically loaded via dlopen. - // GOT[e0] is the module index, with a special value of 0 for the current - // module. GOT[e1] is unused. There only needs to be one module index entry. - if (Expr == R_TLSLD_PC && In.Got->addTlsIndex()) { - AddTlsReloc(In.Got->getTlsIndexOff(), Target->TlsModuleIndexRel, - NeedDynId ? nullptr : &Sym, NeedDynId); - C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); - return 1; - } - - // Global Dynamic is the most general purpose access model. When we know - // the module index and offset of symbol in TLS block we can fill these in - // using static GOT relocations. - if (Expr == R_TLSGD_PC) { - if (In.Got->addDynTlsEntry(Sym)) { - uint64_t Off = In.Got->getGlobalDynOffset(Sym); - AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId); - AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym, - NeedDynOff); - } - C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); - return 1; - } - return 0; -} - +// Notes about General Dynamic and Local Dynamic TLS models below. They may +// require the generation of a pair of GOT entries that have associated dynamic +// relocations. The pair of GOT entries created are of the form GOT[e0] Module +// Index (Used to find pointer to TLS block at run-time) GOT[e1] Offset of +// symbol in TLS block. +// // Returns the number of relocations processed. template static unsigned @@ -212,8 +161,6 @@ if (!Sym.isTls()) return 0; - if (Config->EMachine == EM_ARM) - return handleARMTlsRelocation(Type, Sym, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); @@ -230,10 +177,25 @@ return 1; } + bool CanRelax = Config->EMachine != EM_ARM; + + // If we are producing an executable and the symbol is non-preemptable, it + // must be defined and the code sequence can be relaxed to use Local-Exec. + // + // ARM and RISC-V do not support any relaxations for TLS relocations, however, + // we can omit the DTPMOD dynamic relocations and resolve them at link time + // because them are always 1. This may be necessary for static linking as + // DTPMOD may not be expected at load time. + bool IsLocalInExecutable = !Sym.IsPreemptible && !Config->Shared; + + // Local Dynamic is for access to module local TLS variables, while still + // being suitable for being dynamically loaded via dlopen. GOT[e0] is the + // module index, with a special value of 0 for the current module. GOT[e1] is + // unused. There only needs to be one module index entry. if (oneof( Expr)) { // Local-Dynamic relocs can be relaxed to Local-Exec. - if (!Config->Shared) { + if (CanRelax && !Config->Shared) { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, Offset, Addend, &Sym}); @@ -241,9 +203,14 @@ } if (Expr == R_TLSLD_HINT) return 1; - if (In.Got->addTlsIndex()) - Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, - In.Got->getTlsIndexOff(), nullptr); + if (In.Got->addTlsIndex()) { + if (IsLocalInExecutable) + In.Got->Relocations.push_back( + {R_ADDEND, Target->SymbolicRel, In.Got->getTlsIndexOff(), 1, &Sym}); + else + Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, + In.Got->getTlsIndexOff(), nullptr); + } C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -271,10 +238,16 @@ if (oneof(Expr)) { - if (Config->Shared) { + if (!CanRelax || Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); - Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); + + if (IsLocalInExecutable) + // Write one to the GOT slot. + In.Got->Relocations.push_back( + {R_ADDEND, Target->SymbolicRel, Off, 1, &Sym}); + else + Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); // If the symbol is preemptible we need the dynamic linker to write // the offset too. @@ -313,7 +286,7 @@ // defined. if (oneof(Expr) && - !Config->Shared && !Sym.IsPreemptible) { + CanRelax && IsLocalInExecutable) { C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym}); return 1; }