[ELF][ARM] Merge handleARMTlsRelocation() into handleTlsRelocation()

ARM and RISC-V do not support TLS relaxations. However, for General
Dynamic and Local Dynamic models, if we are producing an executable and
the symbol is non-preemptable, we know it must be defined and the
R_ARM_TLS_DTPMOD32/R_RISCV_TLS_DTPMOD{32,64} dynamic relocation can be
omitted because it is always 1. This may be necessary for static linking
as DTPMOD may not be expected at load time.

Merge handleARMTlsRelocation() into handleTlsRelocation(). This requires
more logic to R_TLSGD_PC and R_TLSLD_PC. Because we use SymbolicRel to
resolve the relocation at link time, R_ARM_TLS_DTPMOD32 can be deleted
from relocateOne(). It cannot be used as a static relocation type.

As a bonus, the additional logic in R_TLSGD_PC code can be shared by the
TLS support for RISC-V (D63220).

Reviewed By: ruiu

Differential Revision: https://reviews.llvm.org/D63333

llvm-svn: 363927
This commit is contained in:
Fangrui Song 2019-06-20 13:53:11 +00:00
parent d91b1edf7b
commit ffed2c96d9
2 changed files with 38 additions and 68 deletions

View File

@ -395,9 +395,6 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const {
case R_ARM_TLS_DTPOFF32:
write32le(Loc, Val);
break;
case R_ARM_TLS_DTPMOD32:
write32le(Loc, 1);
break;
case R_ARM_PREL31:
checkInt(Loc, Val, 31, Type);
write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000));

View File

@ -147,63 +147,12 @@ static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym,
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 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 <class ELFT>
static unsigned
@ -212,8 +161,6 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
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 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
return 1;
}
bool CanRelax = 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 may be necessary for static linking as
// DTPMOD may not be expected at load time.
bool IsLocalInExecutable = !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<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>(
Expr)) {
// Local-Dynamic relocs can be relaxed to Local-Exec.
if (!Config->Shared) {
if (CanRelax && !Config->Shared) {
C.Relocations.push_back(
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type,
Offset, Addend, &Sym});
@ -241,9 +203,14 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
}
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 (IsLocalInExecutable)
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 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) {
if (Config->Shared) {
if (!CanRelax || Config->Shared) {
if (In.Got->addDynTlsEntry(Sym)) {
uint64_t Off = In.Got->getGlobalDynOffset(Sym);
Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym);
if (IsLocalInExecutable)
// 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 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C,
// defined.
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, R_GOT_OFF,
R_TLSIE_HINT>(Expr) &&
!Config->Shared && !Sym.IsPreemptible) {
CanRelax && IsLocalInExecutable) {
C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym});
return 1;
}