Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
lld/ELF/Relocations.cpp
Show First 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, | ||||
// The Dynamic TLS Module Index Relocation for a symbol defined in an | // The Dynamic TLS Module Index Relocation for a symbol defined in an | ||||
// executable is always 1. If the target Symbol is not preemptible then | // executable is always 1. If the target Symbol is not preemptible then | ||||
// we know the offset into the TLS block at static link time. | // we know the offset into the TLS block at static link time. | ||||
bool NeedDynId = Sym.IsPreemptible || Config->Shared; | bool NeedDynId = Sym.IsPreemptible || Config->Shared; | ||||
bool NeedDynOff = Sym.IsPreemptible; | bool NeedDynOff = Sym.IsPreemptible; | ||||
auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { | auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { | ||||
if (Dyn) | if (Dyn) | ||||
In.RelaDyn->addReloc(Type, In.Got, Off, Dest); | Main->RelaDyn->addReloc(Type, In.Got, Off, Dest); | ||||
else | else | ||||
In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); | In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); | ||||
}; | }; | ||||
// Local Dynamic is for access to module local TLS variables, while still | // Local Dynamic is for access to module local TLS variables, while still | ||||
// being suitable for being dynamically loaded via dlopen. | // being suitable for being dynamically loaded via dlopen. | ||||
// GOT[e0] is the module index, with a special value of 0 for the current | // 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. | // module. GOT[e1] is unused. There only needs to be one module index entry. | ||||
Show All 33 Lines | handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, | ||||
if (Config->EMachine == EM_MIPS) | if (Config->EMachine == EM_MIPS) | ||||
return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); | return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); | ||||
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>( | if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC>( | ||||
Expr) && | Expr) && | ||||
Config->Shared) { | Config->Shared) { | ||||
if (In.Got->addDynTlsEntry(Sym)) { | if (In.Got->addDynTlsEntry(Sym)) { | ||||
uint64_t Off = In.Got->getGlobalDynOffset(Sym); | uint64_t Off = In.Got->getGlobalDynOffset(Sym); | ||||
In.RelaDyn->addReloc( | Main->RelaDyn->addReloc( | ||||
{Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0}); | {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0}); | ||||
} | } | ||||
if (Expr != R_TLSDESC_CALL) | if (Expr != R_TLSDESC_CALL) | ||||
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | ||||
return 1; | return 1; | ||||
} | } | ||||
if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>( | if (oneof<R_TLSLD_GOT, R_TLSLD_GOTPLT, R_TLSLD_PC, R_TLSLD_HINT>( | ||||
Expr)) { | Expr)) { | ||||
// Local-Dynamic relocs can be relaxed to Local-Exec. | // Local-Dynamic relocs can be relaxed to Local-Exec. | ||||
if (!Config->Shared) { | if (!Config->Shared) { | ||||
C.Relocations.push_back( | C.Relocations.push_back( | ||||
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, | ||||
Offset, Addend, &Sym}); | Offset, Addend, &Sym}); | ||||
return Target->getTlsGdRelaxSkip(Type); | return Target->getTlsGdRelaxSkip(Type); | ||||
} | } | ||||
if (Expr == R_TLSLD_HINT) | if (Expr == R_TLSLD_HINT) | ||||
return 1; | return 1; | ||||
if (In.Got->addTlsIndex()) | if (In.Got->addTlsIndex()) | ||||
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, | Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, | ||||
In.Got->getTlsIndexOff(), nullptr); | In.Got->getTlsIndexOff(), nullptr); | ||||
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | ||||
return 1; | return 1; | ||||
} | } | ||||
// Local-Dynamic relocs can be relaxed to Local-Exec. | // Local-Dynamic relocs can be relaxed to Local-Exec. | ||||
if (Expr == R_DTPREL && !Config->Shared) { | if (Expr == R_DTPREL && !Config->Shared) { | ||||
C.Relocations.push_back( | C.Relocations.push_back( | ||||
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, | ||||
Show All 14 Lines | if (Expr == R_TLSLD_GOT_OFF) { | ||||
return 1; | return 1; | ||||
} | } | ||||
if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC, | if (oneof<R_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC, | ||||
R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) { | R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC>(Expr)) { | ||||
if (Config->Shared) { | if (Config->Shared) { | ||||
if (In.Got->addDynTlsEntry(Sym)) { | if (In.Got->addDynTlsEntry(Sym)) { | ||||
uint64_t Off = In.Got->getGlobalDynOffset(Sym); | uint64_t Off = In.Got->getGlobalDynOffset(Sym); | ||||
In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); | Main->RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); | ||||
// If the symbol is preemptible we need the dynamic linker to write | // If the symbol is preemptible we need the dynamic linker to write | ||||
// the offset too. | // the offset too. | ||||
uint64_t OffsetOff = Off + Config->Wordsize; | uint64_t OffsetOff = Off + Config->Wordsize; | ||||
if (Sym.IsPreemptible) | if (Sym.IsPreemptible) | ||||
In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym); | Main->RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, | ||||
&Sym); | |||||
else | else | ||||
In.Got->Relocations.push_back( | In.Got->Relocations.push_back( | ||||
{R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); | {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); | ||||
} | } | ||||
C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); | ||||
return 1; | return 1; | ||||
} | } | ||||
// Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec | // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec | ||||
// depending on the symbol being locally defined or not. | // depending on the symbol being locally defined or not. | ||||
if (Sym.IsPreemptible) { | if (Sym.IsPreemptible) { | ||||
C.Relocations.push_back( | C.Relocations.push_back( | ||||
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, | ||||
Offset, Addend, &Sym}); | Offset, Addend, &Sym}); | ||||
if (!Sym.isInGot()) { | if (!Sym.isInGot()) { | ||||
In.Got->addEntry(Sym); | In.Got->addEntry(Sym); | ||||
In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(), | Main->RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(), | ||||
&Sym); | &Sym); | ||||
} | } | ||||
} else { | } else { | ||||
C.Relocations.push_back( | C.Relocations.push_back( | ||||
{Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, | {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, | ||||
Offset, Addend, &Sym}); | Offset, Addend, &Sym}); | ||||
} | } | ||||
return Target->getTlsGdRelaxSkip(Type); | return Target->getTlsGdRelaxSkip(Type); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 289 Lines • ▼ Show 20 Lines | else | ||||
In.Bss->getParent()->addSection(Sec); | In.Bss->getParent()->addSection(Sec); | ||||
// Look through the DSO's dynamic symbol table for aliases and create a | // Look through the DSO's dynamic symbol table for aliases and create a | ||||
// dynamic symbol for each one. This causes the copy relocation to correctly | // dynamic symbol for each one. This causes the copy relocation to correctly | ||||
// interpose any aliases. | // interpose any aliases. | ||||
for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) | for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) | ||||
replaceWithDefined(*Sym, Sec, 0, Sym->Size); | replaceWithDefined(*Sym, Sec, 0, Sym->Size); | ||||
In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); | Main->RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); | ||||
} | } | ||||
// MIPS has an odd notion of "paired" relocations to calculate addends. | // MIPS has an odd notion of "paired" relocations to calculate addends. | ||||
// For example, if a relocation is of R_MIPS_HI16, there must be a | // For example, if a relocation is of R_MIPS_HI16, there must be a | ||||
// R_MIPS_LO16 relocation after that, and an addend is calculated using | // R_MIPS_LO16 relocation after that, and an addend is calculated using | ||||
// the two relocations. | // the two relocations. | ||||
template <class ELFT, class RelTy> | template <class ELFT, class RelTy> | ||||
static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End, | static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End, | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | private: | ||||
ArrayRef<EhSectionPiece> Pieces; | ArrayRef<EhSectionPiece> Pieces; | ||||
size_t I = 0; | size_t I = 0; | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, | static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, | ||||
Symbol *Sym, int64_t Addend, RelExpr Expr, | Symbol *Sym, int64_t Addend, RelExpr Expr, | ||||
RelType Type) { | RelType Type) { | ||||
Partition &Part = IS->getPartition(); | |||||
// Add a relative relocation. If RelrDyn section is enabled, and the | // Add a relative relocation. If RelrDyn section is enabled, and the | ||||
// relocation offset is guaranteed to be even, add the relocation to | // relocation offset is guaranteed to be even, add the relocation to | ||||
// the RelrDyn section, otherwise add it to the RelaDyn section. | // the RelrDyn section, otherwise add it to the RelaDyn section. | ||||
// RelrDyn sections don't support odd offsets. Also, RelrDyn sections | // RelrDyn sections don't support odd offsets. Also, RelrDyn sections | ||||
// don't store the addend values, so we must write it to the relocated | // don't store the addend values, so we must write it to the relocated | ||||
// address. | // address. | ||||
if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { | if (Part.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { | ||||
IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); | IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); | ||||
In.RelrDyn->Relocs.push_back({IS, OffsetInSec}); | Part.RelrDyn->Relocs.push_back({IS, OffsetInSec}); | ||||
return; | return; | ||||
} | } | ||||
In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr, | Part.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, | ||||
Type); | Expr, Type); | ||||
} | } | ||||
template <class ELFT, class GotPltSection> | template <class ELFT, class GotPltSection> | ||||
static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, | static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, | ||||
RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { | RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { | ||||
Plt->addEntry<ELFT>(Sym); | Plt->addEntry<ELFT>(Sym); | ||||
GotPlt->addEntry(Sym); | GotPlt->addEntry(Sym); | ||||
Rel->addReloc( | Rel->addReloc( | ||||
Show All 21 Lines | static void addGotEntry(Symbol &Sym) { | ||||
} | } | ||||
// Otherwise, we emit a dynamic relocation to .rel[a].dyn so that | // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that | ||||
// the GOT slot will be fixed at load-time. | // the GOT slot will be fixed at load-time. | ||||
if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { | if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { | ||||
addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel); | addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel); | ||||
return; | return; | ||||
} | } | ||||
In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got, | Main->RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, | ||||
Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS, | In.Got, Off, &Sym, 0, | ||||
Target->GotRel); | Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel); | ||||
} | } | ||||
// Return true if we can define a symbol in the executable that | // Return true if we can define a symbol in the executable that | ||||
// contains the value/function of a symbol defined in a shared | // contains the value/function of a symbol defined in a shared | ||||
// library. | // library. | ||||
static bool canDefineSymbolInExecutable(Symbol &Sym) { | static bool canDefineSymbolInExecutable(Symbol &Sym) { | ||||
// If the symbol has default visibility the symbol defined in the | // If the symbol has default visibility the symbol defined in the | ||||
// executable will preempt it. | // executable will preempt it. | ||||
Show All 36 Lines | static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, | ||||
if (CanWrite) { | if (CanWrite) { | ||||
// R_GOT refers to a position in the got, even if the symbol is preemptible. | // R_GOT refers to a position in the got, even if the symbol is preemptible. | ||||
bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT; | bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT; | ||||
if (!IsPreemptibleValue) { | if (!IsPreemptibleValue) { | ||||
addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); | addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); | ||||
return; | return; | ||||
} else if (RelType Rel = Target->getDynRel(Type)) { | } else if (RelType Rel = Target->getDynRel(Type)) { | ||||
In.RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); | Sec.getPartition().RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, | ||||
R_ADDEND, Type); | |||||
// MIPS ABI turns using of GOT and dynamic relocations inside out. | // MIPS ABI turns using of GOT and dynamic relocations inside out. | ||||
// While regular ABI uses dynamic relocations to fill up GOT entries | // While regular ABI uses dynamic relocations to fill up GOT entries | ||||
// MIPS ABI requires dynamic linker to fills up GOT entries using | // MIPS ABI requires dynamic linker to fills up GOT entries using | ||||
// specially sorted dynamic symbol table. This affects even dynamic | // specially sorted dynamic symbol table. This affects even dynamic | ||||
// relocations against symbols which do not require GOT entries | // relocations against symbols which do not require GOT entries | ||||
// creation explicitly, i.e. do not have any GOT-relocations. So if | // creation explicitly, i.e. do not have any GOT-relocations. So if | ||||
// a preemptible symbol has a dynamic relocation we anyway have | // a preemptible symbol has a dynamic relocation we anyway have | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | if (unsigned Processed = | ||||
I += (Processed - 1); | I += (Processed - 1); | ||||
return; | return; | ||||
} | } | ||||
// We were asked not to generate PLT entries for ifuncs. Instead, pass the | // We were asked not to generate PLT entries for ifuncs. Instead, pass the | ||||
// direct relocation on through. | // direct relocation on through. | ||||
if (Sym.isGnuIFunc() && Config->ZIfuncNoplt) { | if (Sym.isGnuIFunc() && Config->ZIfuncNoplt) { | ||||
Sym.ExportDynamic = true; | Sym.ExportDynamic = true; | ||||
In.RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); | Main->RelaDyn->addReloc(Type, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); | ||||
return; | return; | ||||
} | } | ||||
// Non-preemptible ifuncs require special handling. First, handle the usual | // Non-preemptible ifuncs require special handling. First, handle the usual | ||||
// case where the symbol isn't one of these. | // case where the symbol isn't one of these. | ||||
if (!Sym.isGnuIFunc() || Sym.IsPreemptible) { | if (!Sym.isGnuIFunc() || Sym.IsPreemptible) { | ||||
// If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. | // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. | ||||
if (needsPlt(Expr) && !Sym.isInPlt()) | if (needsPlt(Expr) && !Sym.isInPlt()) | ||||
▲ Show 20 Lines • Show All 597 Lines • Show Last 20 Lines |