Move target independent code out of x86_64 only path.

The logic for deciding if an undefined symbol should have the value of a
got entry is not target specific.

llvm-svn: 261760
This commit is contained in:
Rafael Espindola 2016-02-24 18:24:23 +00:00
parent ca8e7e2e23
commit 795dc5a0fb
7 changed files with 120 additions and 76 deletions

View File

@ -217,7 +217,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
}
uintX_t SymVA = Body->getVA<ELFT>();
if (Target->needsPlt(Type, *Body)) {
if (Target->needsPlt<ELFT>(Type, *Body)) {
SymVA = Body->getPltVA<ELFT>();
} else if (Target->needsGot(Type, *Body)) {
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true))

View File

@ -93,7 +93,7 @@ public:
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsDynRelative(unsigned Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override;
bool needsPltImpl(uint32_t Type, const 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;
@ -101,6 +101,7 @@ public:
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;
bool refersToGotEntry(uint32_t Type) const override;
private:
void relocateTlsLdToLe(uint8_t *Loc, uint8_t *BufEnd, uint64_t P,
@ -127,7 +128,8 @@ public:
int32_t Index, unsigned RelOff) const override;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override;
bool refersToGotEntry(uint32_t Type) const override;
bool needsPltImpl(uint32_t Type, const 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;
@ -163,7 +165,7 @@ public:
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;
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override;
bool needsPltImpl(uint32_t Type, const 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;
@ -184,7 +186,7 @@ public:
bool isRelRelative(uint32_t Type) const override;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override;
bool needsPltImpl(uint32_t Type, const 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;
@ -220,7 +222,7 @@ public:
void writeGotHeader(uint8_t *Buf) const override;
bool needsCopyRelImpl(uint32_t Type) const override;
bool needsGot(uint32_t Type, SymbolBody &S) const override;
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const override;
bool needsPltImpl(uint32_t Type, const SymbolBody &S) 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;
@ -291,8 +293,43 @@ bool TargetInfo::isSizeRel(uint32_t Type) const { return false; }
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::refersToGotEntry(uint32_t Type) const { return false; }
template <class ELFT>
TargetInfo::PltNeed TargetInfo::needsPlt(uint32_t Type,
const SymbolBody &S) const {
if (needsPltImpl(Type, S))
return Plt_Explicit;
// This handles a non PIC program call to function in a shared library.
// In an ideal world, we could just report an error saying the relocation
// can overflow at runtime.
// In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
// libc.so.
//
// The general idea on how to handle such cases is to create a PLT entry
// and use that as the function value.
//
// For the static linking part, we just return true and everything else
// will use the the PLT entry as the address.
//
// 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).
if (auto *SS = dyn_cast<SharedSymbol<ELFT>>(&S))
if (SS->Sym.getType() == STT_FUNC && !refersToGotEntry(Type))
return Plt_Implicit;
return Plt_No;
}
@ -417,16 +454,14 @@ bool X86TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
return !canRelaxTls(Type, &S);
return Type == R_386_GOT32 || needsPlt(Type, S);
return Type == R_386_GOT32 || needsPlt<ELF32LE>(Type, S);
}
TargetInfo::PltNeed X86TargetInfo::needsPlt(uint32_t Type,
const SymbolBody &S) const {
bool X86TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
if (isGnuIFunc<ELF32LE>(S) ||
(Type == R_386_PLT32 && canBePreempted(&S, true)) ||
(Type == R_386_PC32 && S.isShared()))
return Plt_Explicit;
return Plt_No;
(Type == R_386_PLT32 && canBePreempted(&S, true)))
return true;
return false;
}
bool X86TargetInfo::isGotRelative(uint32_t Type) const {
@ -436,6 +471,10 @@ bool X86TargetInfo::isGotRelative(uint32_t Type) const {
return Type == R_386_GOTOFF;
}
bool X86TargetInfo::refersToGotEntry(uint32_t Type) const {
return Type == R_386_GOT32;
}
void X86TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
uint64_t P, uint64_t SA, uint64_t ZA,
uint8_t *PairedLoc) const {
@ -680,12 +719,16 @@ bool X86_64TargetInfo::needsCopyRelImpl(uint32_t Type) const {
Type == R_X86_64_64;
}
bool X86_64TargetInfo::refersToGotEntry(uint32_t Type) const {
return Type == R_X86_64_GOTPCREL;
}
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)
return !canRelaxTls(Type, &S);
return Type == R_X86_64_GOTPCREL || needsPlt(Type, S);
return refersToGotEntry(Type) || needsPlt<ELF64LE>(Type, S);
}
unsigned X86_64TargetInfo::getTlsGotRel(unsigned Type) const {
@ -707,52 +750,19 @@ bool X86_64TargetInfo::isTlsDynRel(unsigned Type, const SymbolBody &S) const {
return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
}
TargetInfo::PltNeed X86_64TargetInfo::needsPlt(uint32_t Type,
const SymbolBody &S) const {
bool X86_64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
if (needsCopyRel<ELF64LE>(Type, S))
return Plt_No;
return false;
if (isGnuIFunc<ELF64LE>(S))
return Plt_Explicit;
return true;
switch (Type) {
default:
return Plt_No;
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
case R_X86_64_PC32:
// This relocation is defined to have a value of (S + A - P).
// The problems start when a non PIC program calls a function in a shared
// library.
// In an ideal world, we could just report an error saying the relocation
// can overflow at runtime.
// In the real world with glibc, crt1.o has a R_X86_64_PC32 pointing to
// libc.so.
//
// The general idea on how to handle such cases is to create a PLT entry
// and use that as the function value.
//
// For the static linking part, we just return true and everything else
// will use the the PLT entry as the address.
//
// 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).
if (auto *SS = dyn_cast<SharedSymbol<ELF64LE>>(&S)) {
if (SS->Sym.getType() == STT_FUNC)
return Plt_Implicit;
}
return Plt_No;
case R_X86_64_PLT32:
if (canBePreempted(&S, true))
return Plt_Explicit;
return Plt_No;
return true;
return false;
}
}
@ -1044,7 +1054,7 @@ void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
}
bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
if (needsPlt(Type, S))
if (needsPlt<ELF64BE>(Type, S))
return true;
switch (Type) {
@ -1059,12 +1069,11 @@ bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
}
}
TargetInfo::PltNeed PPC64TargetInfo::needsPlt(uint32_t Type,
const SymbolBody &S) const {
bool PPC64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
// These are function calls that need to be redirected through a PLT stub.
if (Type == R_PPC64_REL24 && canBePreempted(&S, false))
return Plt_Explicit;
return Plt_No;
return true;
return false;
}
bool PPC64TargetInfo::isRelRelative(uint32_t Type) const {
@ -1318,24 +1327,23 @@ bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
case R_AARCH64_LD64_GOT_LO12_NC:
return true;
default:
return needsPlt(Type, S);
return needsPlt<ELF64LE>(Type, S);
}
}
TargetInfo::PltNeed AArch64TargetInfo::needsPlt(uint32_t Type,
const SymbolBody &S) const {
bool AArch64TargetInfo::needsPltImpl(uint32_t Type, const SymbolBody &S) const {
if (isGnuIFunc<ELF64LE>(S))
return Plt_Explicit;
return true;
switch (Type) {
default:
return Plt_No;
return false;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
case R_AARCH64_TSTBR14:
if (canBePreempted(&S, true))
return Plt_Explicit;
return Plt_No;
return true;
return false;
}
}
@ -1693,20 +1701,21 @@ bool MipsTargetInfo<ELFT>::needsCopyRelImpl(uint32_t Type) const {
template <class ELFT>
bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, SymbolBody &S) const {
return needsPlt(Type, S) || Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16;
return needsPlt<ELFT>(Type, S) || Type == R_MIPS_GOT16 ||
Type == R_MIPS_CALL16;
}
template <class ELFT>
TargetInfo::PltNeed MipsTargetInfo<ELFT>::needsPlt(uint32_t Type,
const SymbolBody &S) const {
bool MipsTargetInfo<ELFT>::needsPltImpl(uint32_t Type,
const SymbolBody &S) const {
if (needsCopyRel<ELFT>(Type, S))
return Plt_No;
return false;
if (Type == R_MIPS_26 && canBePreempted(&S, false))
return Plt_Explicit;
return true;
if (Type == R_MIPS_HI16 || Type == R_MIPS_LO16 || isRelRelative(Type))
if (S.isShared())
return Plt_Explicit;
return Plt_No;
return true;
return false;
}
template <class ELFT>
@ -1853,5 +1862,14 @@ template bool TargetInfo::needsCopyRel<ELF64LE>(uint32_t,
const SymbolBody &) const;
template bool TargetInfo::needsCopyRel<ELF64BE>(uint32_t,
const SymbolBody &) const;
template TargetInfo::PltNeed
TargetInfo::needsPlt<ELF32LE>(uint32_t, const SymbolBody &) const;
template TargetInfo::PltNeed
TargetInfo::needsPlt<ELF32BE>(uint32_t, const SymbolBody &) const;
template TargetInfo::PltNeed
TargetInfo::needsPlt<ELF64LE>(uint32_t, const SymbolBody &) const;
template TargetInfo::PltNeed
TargetInfo::needsPlt<ELF64BE>(uint32_t, const SymbolBody &) const;
}
}

View File

@ -55,9 +55,12 @@ public:
virtual bool isSizeRel(uint32_t Type) const;
virtual bool needsDynRelative(unsigned Type) const { return false; }
virtual bool needsGot(uint32_t Type, SymbolBody &S) const;
virtual bool refersToGotEntry(uint32_t Type) const;
enum PltNeed { Plt_No, Plt_Explicit, Plt_Implicit };
virtual PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const;
template <class ELFT>
PltNeed needsPlt(uint32_t Type, const SymbolBody &S) const;
virtual 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 = 0;
@ -95,6 +98,7 @@ public:
private:
virtual bool needsCopyRelImpl(uint32_t Type) const;
virtual bool needsPltImpl(uint32_t Type, const SymbolBody &S) const;
};
uint64_t getPPC64TocBase();

View File

@ -362,7 +362,7 @@ void Writer<ELFT>::scanRelocs(
// for the symbol.
TargetInfo::PltNeed NeedPlt = TargetInfo::Plt_No;
if (Body)
NeedPlt = Target->needsPlt(Type, *Body);
NeedPlt = Target->needsPlt<ELFT>(Type, *Body);
if (NeedPlt) {
if (NeedPlt == TargetInfo::Plt_Implicit)
Body->NeedsCopyOrPltAddr = true;

View File

@ -1,4 +1,3 @@
.globl set_data
.type set_data,@function
set_data:
retq

View File

@ -291,5 +291,5 @@
.global _start
_start:
.long bar
.long zed
.long bar@GOT
.long zed@GOT

View File

@ -0,0 +1,23 @@
// REQUIRES: x86
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o
// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
// RUN: ld.lld %t2.o -o %t2.so -shared
// RUN: ld.lld %t.o %t2.so -o %t3
// RUN: llvm-readobj -t -s %t3 | FileCheck %s
.globl _start
_start:
mov $set_data, %eax
// Test that set_data has an address in the .plt
// CHECK: Name: .plt
// CHECK-NEXT: Type: SHT_PROGBITS
// CHECK-NEXT: Flags [
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: SHF_EXECINSTR
// CHECK-NEXT: ]
// CHECK-NEXT: Address: 0x11010
// CHECK: Name: set_data
// CHECK-NEXT: Value: 0x11020