Refactor target independent code.
The rules for when we can relax tls relocations are target independent.
The only things that are target dependent are the relocation values.
llvm-svn: 262748
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 107a7f3..4c6c6d9 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -83,8 +83,10 @@
void writeGotPltHeader(uint8_t *Buf) const override;
unsigned getDynRel(unsigned Type) const override;
unsigned getTlsGotRel(unsigned Type) const override;
+ bool pointsToLocalDynamicGotEntry(unsigned Type) const override;
bool isTlsLocalDynamicRel(unsigned Type) const override;
bool isTlsGlobalDynamicRel(unsigned Type) const override;
+ bool isTlsInitialExecRel(unsigned Type) const override;
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
void writePltZero(uint8_t *Buf) const override;
@@ -97,7 +99,6 @@
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
uint64_t SA, uint64_t ZA = 0,
uint8_t *PairedLoc = nullptr) const override;
- bool canRelaxTlsImpl(unsigned Type, const SymbolBody *S) const override;
unsigned relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
uint64_t SA, const SymbolBody *S) const override;
bool isGotRelative(uint32_t Type) const override;
@@ -118,8 +119,10 @@
public:
X86_64TargetInfo();
unsigned getTlsGotRel(unsigned Type) const override;
+ bool pointsToLocalDynamicGotEntry(unsigned Type) const override;
bool isTlsLocalDynamicRel(unsigned Type) const override;
bool isTlsGlobalDynamicRel(unsigned Type) const override;
+ bool isTlsInitialExecRel(unsigned Type) const override;
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
void writeGotPltHeader(uint8_t *Buf) const override;
void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
@@ -134,7 +137,6 @@
uint64_t SA, uint64_t ZA = 0,
uint8_t *PairedLoc = nullptr) const override;
bool isRelRelative(uint32_t Type) const override;
- bool canRelaxTlsImpl(unsigned Type, const SymbolBody *S) const override;
bool isSizeRel(uint32_t Type) const override;
unsigned relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
uint64_t SA, const SymbolBody *S) const override;
@@ -177,6 +179,7 @@
AArch64TargetInfo();
unsigned getDynRel(unsigned Type) const override;
bool isTlsGlobalDynamicRel(unsigned Type) const override;
+ bool isTlsInitialExecRel(unsigned Type) const override;
void writeGotPlt(uint8_t *Buf, uint64_t Plt) const override;
void writePltZero(uint8_t *Buf) const override;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
@@ -192,7 +195,6 @@
uint8_t *PairedLoc = nullptr) const override;
unsigned relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
uint64_t SA, const SymbolBody *S) const override;
- bool canRelaxTlsImpl(unsigned Type, const SymbolBody *S) const override;
private:
void relocateTlsGdToLe(unsigned Type, uint8_t *Loc, uint8_t *BufEnd,
@@ -264,10 +266,23 @@
bool TargetInfo::canRelaxTls(unsigned Type, const SymbolBody *S) const {
if (Config->Shared || (S && !S->isTls()))
return false;
- return canRelaxTlsImpl(Type, S);
-}
-bool TargetInfo::canRelaxTlsImpl(unsigned Type, const SymbolBody *S) const {
+ // We know we are producing an executable.
+
+ // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec
+ // depending on the symbol being locally defined or not.
+ if (isTlsGlobalDynamicRel(Type))
+ return true;
+
+ // Local-Dynamic relocs can be relaxed to Local-Exec.
+ if (isTlsLocalDynamicRel(Type))
+ return true;
+
+ // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally
+ // defined.
+ if (isTlsInitialExecRel(Type))
+ return !canBePreempted(S);
+
return false;
}
@@ -341,10 +356,14 @@
return Plt_No;
}
-bool TargetInfo::isTlsLocalDynamicRel(unsigned Type) const {
+bool TargetInfo::isTlsInitialExecRel(unsigned Type) const { return false; }
+
+bool TargetInfo::pointsToLocalDynamicGotEntry(unsigned Type) const {
return false;
}
+bool TargetInfo::isTlsLocalDynamicRel(unsigned Type) const { return false; }
+
bool TargetInfo::isTlsGlobalDynamicRel(unsigned Type) const {
return false;
}
@@ -398,9 +417,17 @@
}
bool X86TargetInfo::isTlsLocalDynamicRel(unsigned Type) const {
+ return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM;
+}
+
+bool X86TargetInfo::pointsToLocalDynamicGotEntry(unsigned Type) const {
return Type == R_386_TLS_LDM;
}
+bool X86TargetInfo::isTlsInitialExecRel(unsigned Type) const {
+ return Type == R_386_TLS_IE || Type == R_386_TLS_GOTIE;
+}
+
bool X86TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
if (Type == R_386_TLS_LE || Type == R_386_TLS_LE_32 ||
Type == R_386_TLS_GOTIE)
@@ -528,12 +555,6 @@
}
}
-bool X86TargetInfo::canRelaxTlsImpl(unsigned Type, const SymbolBody *S) const {
- return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM ||
- Type == R_386_TLS_GD || (Type == R_386_TLS_IE && !canBePreempted(S)) ||
- (Type == R_386_TLS_GOTIE && !canBePreempted(S));
-}
-
bool X86TargetInfo::needsDynRelative(unsigned Type) const {
return Config->Shared && Type == R_386_TLS_IE;
}
@@ -740,14 +761,22 @@
return R_X86_64_PC32;
}
+bool X86_64TargetInfo::isTlsInitialExecRel(unsigned Type) const {
+ return Type == R_X86_64_GOTTPOFF;
+}
+
bool X86_64TargetInfo::isTlsGlobalDynamicRel(unsigned Type) const {
return Type == R_X86_64_TLSGD;
}
-bool X86_64TargetInfo::isTlsLocalDynamicRel(unsigned Type) const {
+bool X86_64TargetInfo::pointsToLocalDynamicGotEntry(unsigned Type) const {
return Type == R_X86_64_TLSLD;
}
+bool X86_64TargetInfo::isTlsLocalDynamicRel(unsigned Type) const {
+ return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_TLSLD;
+}
+
bool X86_64TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
}
@@ -775,13 +804,6 @@
return Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64;
}
-bool X86_64TargetInfo::canRelaxTlsImpl(unsigned Type,
- const SymbolBody *S) const {
- return Type == R_X86_64_TLSGD || Type == R_X86_64_TLSLD ||
- Type == R_X86_64_DTPOFF32 ||
- (Type == R_X86_64_GOTTPOFF && !canBePreempted(S));
-}
-
// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
// x86-x64 linker optimizations, http://www.akkadia.org/drepper/tls.pdf) shows
// how LD can be optimized to LE:
@@ -1221,6 +1243,11 @@
Type == R_AARCH64_TLSDESC_CALL;
}
+bool AArch64TargetInfo::isTlsInitialExecRel(unsigned Type) const {
+ return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
+ Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
+}
+
unsigned AArch64TargetInfo::getDynRel(unsigned Type) const {
if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64)
return Type;
@@ -1459,23 +1486,6 @@
}
}
-bool AArch64TargetInfo::canRelaxTlsImpl(unsigned Type,
- const SymbolBody *S) const {
- // Global-Dynamic relocs can be relaxed to Initial-Exec if the target is
- // an executable. And if the target is local it can also be fully relaxed to
- // Local-Exec.
- if (isTlsGlobalDynamicRel(Type))
- return !canBePreempted(S);
-
- // Initial-Exec relocs can be relaxed to Local-Exec if the target is a local
- // symbol.
- if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
- Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
- return !canBePreempted(S);
-
- return false;
-}
-
unsigned AArch64TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd,
uint32_t Type, uint64_t P, uint64_t SA,
const SymbolBody *S) const {