diff options
author | Peter Smith <peter.smith@arm.com> | 2016-07-21 17:00:13 +0100 |
---|---|---|
committer | Peter Smith <peter.smith@arm.com> | 2016-07-21 17:00:13 +0100 |
commit | 848ea4f7264921eb1d77c2559ba6ff13e9413426 (patch) | |
tree | 821331250cbe0f7c8fbcee53ded04a40cff24879 | |
parent | 8d4b1bf9054263588be95152197813fd7f410daf (diff) |
Some experimental support with TLS relaxation for static linking.linaro-local/tls-experiments
Not quite good enough yet as ifunc isn't working properly.
Change-Id: I291d51647f0b1777615d8f7d19729777cad10764
-rw-r--r-- | ELF/OutputSections.cpp | 13 | ||||
-rw-r--r-- | ELF/Relocations.cpp | 32 | ||||
-rw-r--r-- | ELF/Target.cpp | 19 | ||||
-rw-r--r-- | ELF/Target.h | 1 | ||||
-rw-r--r-- | ELF/Writer.cpp | 13 |
5 files changed, 60 insertions, 18 deletions
diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index 7ff5ba914..f5b077188 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -155,6 +155,7 @@ template <class ELFT> bool GotSection<ELFT>::addDynTlsEntry(SymbolBody &Sym) { if (Sym.GlobalDynIndex != -1U) return false; Sym.GlobalDynIndex = Entries.size(); + llvm::outs() << "Adding DynTlsEntry: " << Sym.GlobalDynIndex << "\n"; // Global Dynamic TLS entries take two GOT slots. Entries.push_back(nullptr); Entries.push_back(&Sym); @@ -288,16 +289,28 @@ template <class ELFT> void GotSection<ELFT>::writeMipsGot(uint8_t *&Buf) { template <class ELFT> void GotSection<ELFT>::writeTo(uint8_t *Buf) { if (Config->EMachine == EM_MIPS) writeMipsGot(Buf); + bool NoDynRel = Symtab<ELFT>::X->getSharedFiles().empty() && !Config->Pic; for (const SymbolBody *B : Entries) { uint8_t *Entry = Buf; Buf += sizeof(uintX_t); if (!B) continue; + if (NoDynRel && B->GlobalDynIndex != -1U && Config->EMachine == EM_ARM) { + llvm::outs() << "writing module index into GOT\n"; + write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)> + (Entry - sizeof(uintX_t), 1); + } if (B->isPreemptible()) continue; // The dynamic linker will take care of it. uintX_t VA = B->getVA<ELFT>(); write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(Entry, VA); } + if (NoDynRel && Config->EMachine == EM_ARM && TlsIndexOff != -1U) { + // Tls module index in GOT is 1 with no dynamic relocation + llvm::outs() << "writing module index into GOT\n"; + uint8_t *TlsIndexEntry = Buf + TlsIndexOff; + write<uintX_t, ELFT::TargetEndianness, sizeof(uintX_t)>(TlsIndexEntry, 1); + } } template <class ELFT> diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 7df92d50c..87d1341de 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -83,16 +83,18 @@ static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { return Body.isPreemptible(); } -// This function is similar to the `handleTlsRelocation`. MIPS does not support -// any relaxations for TLS relocations so by factoring out MIPS handling into -// the separate function we can simplify the code and does not pollute -// `handleTlsRelocation` by MIPS `ifs` statements. +// This function is similar to the `handleTlsRelocation`. MIPS and ARM do not +// support any relaxations for TLS relocations so by factoring out the +// handling into the separate function we can simplify the code and does not +// pollute `handleTlsRelocation` by target specific `if` statements. template <class ELFT> static unsigned -handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, - InputSectionBase<ELFT> &C, typename ELFT::uint Offset, - typename ELFT::uint Addend, RelExpr Expr) { - if (Expr == R_MIPS_TLSLD) { +handleNoRelaxTlsRelocation(uint32_t Type, SymbolBody &Body, + InputSectionBase<ELFT> &C, + typename ELFT::uint Offset, + typename ELFT::uint Addend, RelExpr Expr) { + if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { + llvm::outs() << "Add GOT entry for R_TLSLD_PC\n"; if (Out<ELFT>::Got->addTlsIndex()) Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out<ELFT>::Got, Out<ELFT>::Got->getTlsIndexOff(), false, @@ -106,9 +108,12 @@ handleMipsTlsRelocation(uint32_t Type, SymbolBody &Body, uintX_t Off = Out<ELFT>::Got->getGlobalDynOffset(Body); Out<ELFT>::RelaDyn->addReloc( {Target->TlsModuleIndexRel, Out<ELFT>::Got, Off, false, &Body, 0}); - Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got, - Off + (uintX_t)sizeof(uintX_t), false, - &Body, 0}); + // If the symbol is preemptible we need the dynamic linker to write + // the offset too. + if (isPreemptible(Body, Type) || Config->EMachine == EM_MIPS) + Out<ELFT>::RelaDyn->addReloc({Target->TlsOffsetRel, Out<ELFT>::Got, + Off + (uintX_t)sizeof(uintX_t), false, + &Body, 0}); } C.Relocations.push_back({Expr, Type, &C, Offset, Addend, &Body}); return 1; @@ -130,8 +135,9 @@ static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, typedef typename ELFT::uint uintX_t; - if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, Expr); + if (!Target->canRelaxTls()) + return handleNoRelaxTlsRelocation<ELFT>(Type, Body, C, Offset, Addend, + Expr); if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_HINT) && Config->Shared) { diff --git a/ELF/Target.cpp b/ELF/Target.cpp index 3b11c504d..e8da78476 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -178,6 +178,7 @@ public: RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; uint32_t getDynRel(uint32_t Type) const override; uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; + bool canRelaxTls() const override; bool isTlsLocalDynamicRel(uint32_t Type) const override; bool isTlsGlobalDynamicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; @@ -197,6 +198,7 @@ public: RelExpr getRelExpr(uint32_t Type, const SymbolBody &S) const override; uint64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; + bool canRelaxTls() const override; bool isTlsLocalDynamicRel(uint32_t Type) const override; bool isTlsGlobalDynamicRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; @@ -274,6 +276,10 @@ RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, return Expr; } +bool TargetInfo::canRelaxTls() const { + return true; +} + void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } @@ -1629,7 +1635,10 @@ void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: + case R_ARM_TARGET1: case R_ARM_TLS_GD32: + case R_ARM_TLS_LDM32: + case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: @@ -1757,6 +1766,7 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf, case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: + case R_ARM_TARGET1: case R_ARM_TLS_GD32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: @@ -1819,6 +1829,10 @@ uint64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf, } } +bool ARMTargetInfo::canRelaxTls() const { + return false; +} + bool ARMTargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return Type == R_ARM_TLS_LDO32 || Type == R_ARM_TLS_LDM32; } @@ -1915,6 +1929,11 @@ uint32_t MipsTargetInfo<ELFT>::getDynRel(uint32_t Type) const { } template <class ELFT> +bool MipsTargetInfo<ELFT>::canRelaxTls() const { + return false; +} + +template <class ELFT> bool MipsTargetInfo<ELFT>::isTlsLocalDynamicRel(uint32_t Type) const { return Type == R_MIPS_TLS_LDM; } diff --git a/ELF/Target.h b/ELF/Target.h index 67bf3a27f..578053542 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -96,6 +96,7 @@ public: virtual RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const; + virtual bool canRelaxTls() const; virtual void relaxGot(uint8_t *Loc, uint64_t Val) const; virtual void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; virtual void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 9e5cf23b8..1e5c1d070 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -595,10 +595,11 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_"); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For - // static linking the linker is required to optimize away any references to - // __tls_get_addr, so it's not defined anywhere. Create a hidden definition - // to avoid the undefined symbol error. - if (!isOutputDynamic<ELFT>()) + // systems other than ARM when static linking the linker is required to + // optimize away any references to __tls_get_addr, so it's not + // defined anywhere. Create a hidden definition to avoid the undefined symbol + // error. + if (!isOutputDynamic<ELFT>() && !Config->EMachine == EM_ARM) Symtab.addIgnored("__tls_get_addr"); auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym1, @@ -875,8 +876,10 @@ template <class ELFT> void Writer<ELFT>::addPredefinedSections() { Out<ELFT>::RelaPlt->Static = !isOutputDynamic<ELFT>(); } - if (needsGot()) + if (needsGot()) { Add(Out<ELFT>::Got); + llvm::outs() << "Needs GOT\n"; + } if (Out<ELFT>::GotPlt && !Out<ELFT>::GotPlt->empty()) Add(Out<ELFT>::GotPlt); if (!Out<ELFT>::Plt->empty()) |