aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Smith <peter.smith@arm.com>2016-07-21 17:00:13 +0100
committerPeter Smith <peter.smith@arm.com>2016-07-21 17:00:13 +0100
commit848ea4f7264921eb1d77c2559ba6ff13e9413426 (patch)
tree821331250cbe0f7c8fbcee53ded04a40cff24879
parent8d4b1bf9054263588be95152197813fd7f410daf (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.cpp13
-rw-r--r--ELF/Relocations.cpp32
-rw-r--r--ELF/Target.cpp19
-rw-r--r--ELF/Target.h1
-rw-r--r--ELF/Writer.cpp13
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())