Index: ELF/Relocations.cpp =================================================================== --- ELF/Relocations.cpp +++ 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. +// Notes about General Dynamic and Local Dynamic relocations 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. // -// 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; -} - // 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 Relax = 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 is necessary for static linking as there + // will be no dynamic loader to resolve them at load-time. + bool IsLocalExec = !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 (Relax && !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 (IsLocalExec) + 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 (!Relax || Config->Shared) { if (In.Got->addDynTlsEntry(Sym)) { uint64_t Off = In.Got->getGlobalDynOffset(Sym); - Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); + + if (IsLocalExec) + // 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) { + Relax && IsLocalExec) { C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym}); return 1; }