From a630d0f01b7753afde06f9ed077289083728986a Mon Sep 17 00:00:00 2001 From: Peter Smith Date: Fri, 7 Apr 2017 09:09:48 +0000 Subject: [PATCH] [ELF] Split handleNoRelaxTlsRelocation into ARM and Mips specific impls The handleNoRelaxTlsRelocation handled both ARM and Mips as at a high-level the actions of what to do when encountering a local dynamic or global dynamic TLS relocation are the same. However due to Mips using a custom GOT the differences of the implementation are enough that the function became difficult to understand. This change replaces handleNotRelaxTlsRelocation into handleARMTlsRelocation() and handleMipsTlsRelocation() so that the ARM and Mips specific code is isolated. Differential Revision: https://reviews.llvm.org/D31748 llvm-svn: 299750 --- lld/ELF/Relocations.cpp | 92 ++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 7ab886b627943..c9dc0b65f77a7 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -95,21 +95,63 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { return Body.isPreemptible(); } -// This function is similar to the `handleTlsRelocation`. ARM and MIPS do not -// support any relaxations for TLS relocations so by factoring out ARM and MIPS +// This function is similar to the `handleTlsRelocation`. MIPS does not +// support any relaxations for TLS relocations so by factoring out MIPS // handling in to the separate function we can simplify the code and do not -// pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements. -template -static unsigned handleNoRelaxTlsRelocation(GOT *Got, uint32_t Type, - SymbolBody &Body, - InputSectionBase &C, uint64_t Offset, - int64_t Addend, RelExpr Expr) { +// pollute other `handleTlsRelocation` by MIPS `ifs` statements. +// Mips has a custom MipsGotSection that handles the writing of GOT entries +// without dynamic relocations. +template +static unsigned handleMipsTlsRelocation(MipsGotSection *Got, uint32_t Type, + SymbolBody &Body, InputSectionBase &C, + uint64_t Offset, int64_t Addend, + RelExpr Expr) { + if (Expr == R_MIPS_TLSLD) { + if (Got->addTlsIndex() && Config->Pic) + In::RelaDyn->addReloc({Target->TlsModuleIndexRel, Got, + Got->getTlsIndexOff(), false, nullptr, 0}); + C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + return 1; + } + + if (Expr == R_MIPS_TLSGD) { + if (Got->addDynTlsEntry(Body) && Body.isPreemptible()) { + uint64_t Off = Got->getGlobalDynOffset(Body); + In::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, Got, Off, false, &Body, 0}); + if (Body.isPreemptible()) + In::RelaDyn->addReloc({Target->TlsOffsetRel, Got, + Off + Config->Wordsize, false, &Body, 0}); + } + C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); + return 1; + } + 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 +template +static unsigned handleARMTlsRelocation(GotSection *Got, uint32_t Type, + SymbolBody &Body, InputSectionBase &C, + uint64_t Offset, int64_t Addend, + RelExpr Expr) { auto addModuleReloc = [&](uint64_t Off, bool LD) { // The Dynamic TLS Module Index Relocation can be statically resolved to 1 - // if we know that we are linking an executable. For ARM we resolve the - // relocation when writing the Got. MIPS has a custom Got implementation - // that writes the Module index in directly. - if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM) + // if we know that the TLS Symbol is in an executable. + if (!Body.isPreemptible() && !Config->Pic) Got->Relocations.push_back( {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body}); else { @@ -119,16 +161,21 @@ static unsigned handleNoRelaxTlsRelocation(GOT *Got, uint32_t Type, } }; - if (isRelExprOneOf(Expr)) { - if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM)) - addModuleReloc(Got->getTlsIndexOff(), true); + // 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 && Got->addTlsIndex()) { + addModuleReloc(Got->getTlsIndexOff(), true); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } - if (isRelExprOneOf(Expr)) { - if (Got->addDynTlsEntry(Body) && - (Body.isPreemptible() || Config->EMachine == EM_ARM)) { + // 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 (Got->addDynTlsEntry(Body)) { uint64_t Off = Got->getGlobalDynOffset(Body); addModuleReloc(Off, false); if (Body.isPreemptible()) @@ -138,7 +185,6 @@ static unsigned handleNoRelaxTlsRelocation(GOT *Got, uint32_t Type, C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } - return 0; } @@ -154,11 +200,11 @@ handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, return 0; if (Config->EMachine == EM_ARM) - return handleNoRelaxTlsRelocation(In::Got, Type, Body, C, - Offset, Addend, Expr); + return handleARMTlsRelocation(In::Got, Type, Body, C, Offset, + Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleNoRelaxTlsRelocation(In::MipsGot, Type, Body, C, - Offset, Addend, Expr); + return handleMipsTlsRelocation(In::MipsGot, Type, Body, C, + Offset, Addend, Expr); bool IsPreemptible = isPreemptible(Body, Type); if (isRelExprOneOf(Expr) &&