Use the plt entry as the address of some symbols.
This is the function equivalent of a copy relocation.
Since functions are expected to change sizes, we cannot use copy
relocations. In situations where one would be needed, what is done
instead is:
* Create a plt entry
* Output an undefined symbol whose addr is the plt entry.
The dynamic linker makes sure any shared library uses the plt entry as
the function address.
llvm-svn: 260224
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 70edfd3..0352c79 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -90,8 +90,8 @@
int32_t Index, unsigned RelOff) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
bool needsDynRelative(unsigned Type) const override;
- bool needsGot(uint32_t Type, const SymbolBody &S) const override;
- bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+ bool needsGot(uint32_t Type, SymbolBody &S) const override;
+ bool needsPlt(uint32_t Type, SymbolBody &S) 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;
@@ -121,8 +121,8 @@
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
- bool needsGot(uint32_t Type, const SymbolBody &S) const override;
- bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+ bool needsGot(uint32_t Type, SymbolBody &S) const override;
+ bool needsPlt(uint32_t Type, SymbolBody &S) 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;
@@ -157,8 +157,8 @@
PPC64TargetInfo();
void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
int32_t Index, unsigned RelOff) const override;
- bool needsGot(uint32_t Type, const SymbolBody &S) const override;
- bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+ bool needsGot(uint32_t Type, SymbolBody &S) const override;
+ bool needsPlt(uint32_t Type, SymbolBody &S) 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;
@@ -176,8 +176,8 @@
unsigned getTlsGotRel(unsigned Type = -1) const override;
bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
- bool needsGot(uint32_t Type, const SymbolBody &S) const override;
- bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+ bool needsGot(uint32_t Type, SymbolBody &S) const override;
+ bool needsPlt(uint32_t Type, SymbolBody &S) 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;
@@ -197,8 +197,8 @@
unsigned getDynRel(unsigned Type) const override;
void writeGotHeader(uint8_t *Buf) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
- bool needsGot(uint32_t Type, const SymbolBody &S) const override;
- bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+ bool needsGot(uint32_t Type, SymbolBody &S) const override;
+ bool needsPlt(uint32_t Type, SymbolBody &S) 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;
@@ -263,13 +263,9 @@
bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
bool TargetInfo::isSizeRel(uint32_t Type) const { return false; }
-bool TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
- return false;
-}
+bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return false; }
-bool TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
- return false;
-}
+bool TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { return false; }
unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
uint64_t P, uint64_t SA,
@@ -376,7 +372,7 @@
return false;
}
-bool X86TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+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);
if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
@@ -384,7 +380,7 @@
return Type == R_386_GOT32 || needsPlt(Type, S);
}
-bool X86TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool X86TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
return isGnuIFunc<ELF32LE>(S) ||
(Type == R_386_PLT32 && canBePreempted(&S, true)) ||
(Type == R_386_PC32 && S.isShared());
@@ -646,7 +642,7 @@
return false;
}
-bool X86_64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool X86_64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
if (Type == R_X86_64_TLSGD)
return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
if (Type == R_X86_64_GOTTPOFF)
@@ -658,7 +654,7 @@
return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
}
-bool X86_64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool X86_64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
if (needsCopyRel(Type, S))
return false;
if (isGnuIFunc<ELF64LE>(S))
@@ -684,17 +680,19 @@
// For the static linking part, we just return true and everything else
// will use the the PLT entry as the address.
//
- // The remaining (unimplemented) problem is making sure pointer equality
- // still works. We need the help of the dynamic linker for that. We
- // let it know that we have a direct reference to a so symbol by creating
- // an undefined symbol with a non zero st_value. Seeing that, the
- // dynamic linker resolves the symbol to the value of the symbol we created.
- // This is true even for got entries, so pointer equality is maintained.
- // To avoid an infinite loop, the only entry that points to the
- // real function is a dedicated got entry used by the plt. That is
- // identified by special relocation types (R_X86_64_JUMP_SLOT,
+ // The remaining problem is making sure pointer equality still works. We
+ // need the help of the dynamic linker for that. We let it know that we have
+ // a direct reference to a so symbol by creating an undefined symbol with a
+ // non zero st_value. Seeing that, the dynamic linker resolves the symbol to
+ // the value of the symbol we created. This is true even for got entries, so
+ // pointer equality is maintained. To avoid an infinite loop, the only entry
+ // that points to the real function is a dedicated got entry used by the
+ // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
// R_386_JMP_SLOT, etc).
- return S.isShared();
+ if (!S.isShared())
+ return false;
+ S.NeedsCopyOrPltAddr = true;
+ return true;
case R_X86_64_PLT32:
return canBePreempted(&S, true);
}
@@ -989,7 +987,7 @@
write32be(Buf + 28, 0x4e800420); // bctr
}
-bool PPC64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
if (needsPlt(Type, S))
return true;
@@ -1005,7 +1003,7 @@
}
}
-bool PPC64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool PPC64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
// These are function calls that need to be redirected through a PLT stub.
return Type == R_PPC64_REL24 && canBePreempted(&S, false);
}
@@ -1240,7 +1238,7 @@
}
}
-bool AArch64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
switch (Type) {
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
@@ -1252,7 +1250,7 @@
}
}
-bool AArch64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool AArch64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
if (isGnuIFunc<ELF64LE>(S))
return true;
switch (Type) {
@@ -1439,12 +1437,12 @@
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, SymbolBody &S) const {
return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16;
}
template <class ELFT>
-bool MipsTargetInfo<ELFT>::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool MipsTargetInfo<ELFT>::needsPlt(uint32_t Type, SymbolBody &S) const {
return false;
}