// for detailed description:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
// As the first approach, we can just store addresses for all symbols.
- if (Config->EMachine != EM_MIPS && canBePreempted(B, false))
+ if (Config->EMachine != EM_MIPS && canBePreempted(B))
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);
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
-bool elf2::canBePreempted(const SymbolBody *Body, bool NeedsGot) {
+bool elf2::canBePreempted(const SymbolBody *Body) {
if (!Body)
return false; // Body is a local symbol.
if (Body->isShared())
if (!Body->isWeak())
return true;
- // This is an horrible corner case. Ideally we would like to say that any
- // undefined symbol can be preempted so that the dynamic linker has a
- // chance of finding it at runtime.
- //
- // The problem is that the code sequence used to test for weak undef
- // functions looks like
- // if (func) func()
- // If the code is -fPIC the first reference is a load from the got and
- // everything works.
- // If the code is not -fPIC there is no reasonable way to solve it:
- // * A relocation writing to the text segment will fail (it is ro).
- // * A copy relocation doesn't work for functions.
- // * The trick of using a plt entry as the address would fail here since
- // the plt entry would have a non zero address.
- // Since we cannot do anything better, we just resolve the symbol to 0 and
- // don't produce a dynamic relocation.
- //
- // As an extra hack, assume that if we are producing a shared library the
- // user knows what he or she is doing and can handle a dynamic relocation.
- return Config->Shared || NeedsGot;
+ // Ideally the static linker should see a definition for every symbol, but
+ // shared object are normally allowed to have undefined references that the
+ // static linker never sees a definition for.
+ if (Config->Shared)
+ return true;
+
+ // Otherwise, just resolve to 0.
+ return false;
}
if (!Config->Shared)
return false;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsDynRelative(unsigned Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
- bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
+ bool needsPltImpl(uint32_t Type) const override;
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 needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
bool refersToGotEntry(uint32_t Type) const override;
- bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
+ bool needsPltImpl(uint32_t Type) const override;
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;
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
- bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
+ bool needsPltImpl(uint32_t Type) const override;
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 isRelRelative(uint32_t Type) const override;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
- bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
+ bool needsPltImpl(uint32_t Type) const override;
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;
void writeGotHeader(uint8_t *Buf) const override;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
- bool needsPltImpl(uint32_t Type, const SymbolBody &S) const override;
+ bool needsPltImpl(uint32_t Type) const override;
void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
uint64_t S, uint64_t ZA = 0,
uint8_t *PairedLoc = nullptr) const override;
bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return false; }
-bool TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
- return false;
-}
+bool TargetInfo::needsPltImpl(uint32_t Type) const { return false; }
bool TargetInfo::refersToGotEntry(uint32_t Type) const { return false; }
const SymbolBody &S) const {
if (isGnuIFunc<ELFT>(S))
return Plt_Explicit;
- if (needsPltImpl(Type, S))
+ if (canBePreempted(&S) && needsPltImpl(Type))
return Plt_Explicit;
// This handles a non PIC program call to function in a shared library.
Type == R_386_TLS_GOTIE)
return Config->Shared;
if (Type == R_386_TLS_IE)
- return canBePreempted(&S, true);
+ return canBePreempted(&S);
return Type == R_386_TLS_GD;
}
bool X86TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
if (S.IsTls && Type == R_386_TLS_GD)
- return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
+ return Target->canRelaxTls(Type, &S) && canBePreempted(&S);
if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
return !canRelaxTls(Type, &S);
return Type == R_386_GOT32 || needsPlt<ELF32LE>(Type, S);
}
-bool X86TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
- return Type == R_386_PLT32 && canBePreempted(&S, true);
+bool X86TargetInfo::needsPltImpl(uint32_t Type) const {
+ return Type == R_386_PLT32;
}
bool X86TargetInfo::isGotRelative(uint32_t Type) const {
if (Config->Shared || (S && !S->IsTls))
return false;
return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM ||
- Type == R_386_TLS_GD ||
- (Type == R_386_TLS_IE && !canBePreempted(S, true)) ||
- (Type == R_386_TLS_GOTIE && !canBePreempted(S, true));
+ 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 {
const SymbolBody *S) const {
switch (Type) {
case R_386_TLS_GD:
- if (canBePreempted(S, true))
+ if (canBePreempted(S))
relocateTlsGdToIe(Loc, BufEnd, P, SA);
else
relocateTlsGdToLe(Loc, BufEnd, P, SA);
bool X86_64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
if (Type == R_X86_64_TLSGD)
- return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
+ return Target->canRelaxTls(Type, &S) && canBePreempted(&S);
if (Type == R_X86_64_GOTTPOFF)
return !canRelaxTls(Type, &S);
return refersToGotEntry(Type) || needsPlt<ELF64LE>(Type, S);
return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
}
-bool X86_64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
- switch (Type) {
- default:
- return Plt_No;
- case R_X86_64_PLT32:
- if (canBePreempted(&S, true))
- return true;
- return false;
- }
+bool X86_64TargetInfo::needsPltImpl(uint32_t Type) const {
+ return Type == R_X86_64_PLT32;
}
bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
return false;
return Type == R_X86_64_TLSGD || Type == R_X86_64_TLSLD ||
Type == R_X86_64_DTPOFF32 ||
- (Type == R_X86_64_GOTTPOFF && !canBePreempted(S, true));
+ (Type == R_X86_64_GOTTPOFF && !canBePreempted(S));
}
// "Ulrich Drepper, ELF Handling For Thread-Local Storage" (5.5
relocateTlsIeToLe(Loc, BufEnd, P, SA);
return 0;
case R_X86_64_TLSGD: {
- if (canBePreempted(S, true))
+ if (canBePreempted(S))
relocateTlsGdToIe(Loc, BufEnd, P, SA);
else
relocateTlsGdToLe(Loc, BufEnd, P, SA);
}
}
-bool PPC64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
+bool PPC64TargetInfo::needsPltImpl(uint32_t Type) const {
// These are function calls that need to be redirected through a PLT stub.
- if (Type == R_PPC64_REL24 && canBePreempted(&S, false))
- return true;
- return false;
+ return Type == R_PPC64_REL24;
}
bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
}
}
-bool AArch64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
+bool AArch64TargetInfo::needsPltImpl(uint32_t Type) const {
switch (Type) {
default:
return false;
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
- if (canBePreempted(&S, true))
- return true;
- return false;
+ return true;
}
}
// an executable. And if the target is local it can also be fully relaxed to
// Local-Exec.
if (isTlsGlobalDynamicRel(Type))
- return !canBePreempted(S, true);
+ 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, true);
+ return !canBePreempted(S);
return false;
}
case R_AARCH64_TLSDESC_LD64_LO12_NC:
case R_AARCH64_TLSDESC_ADD_LO12_NC:
case R_AARCH64_TLSDESC_CALL: {
- if (canBePreempted(S, true))
+ if (canBePreempted(S))
fatal("Unsupported TLS optimization");
uint64_t X = S ? S->getVA<ELF64LE>() : SA;
relocateTlsGdToLe(Type, Loc, BufEnd, P, X);
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::needsPltImpl(uint32_t Type,
- const SymbolBody &S) const {
- if (Type == R_MIPS_26 && canBePreempted(&S, false))
- return true;
- return false;
+bool MipsTargetInfo<ELFT>::needsPltImpl(uint32_t Type) const {
+ return Type == R_MIPS_26;
}
template <class ELFT>