summaryrefslogtreecommitdiff
path: root/ELF/Target.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Target.cpp')
-rw-r--r--ELF/Target.cpp178
1 files changed, 153 insertions, 25 deletions
diff --git a/ELF/Target.cpp b/ELF/Target.cpp
index 8d54c93570fa..6d42dbe86e54 100644
--- a/ELF/Target.cpp
+++ b/ELF/Target.cpp
@@ -122,7 +122,6 @@ private:
class X86_64TargetInfo final : public TargetInfo {
public:
X86_64TargetInfo();
- unsigned getPltRefReloc(unsigned Type) const override;
bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override;
void writeGotPltHeaderEntries(uint8_t *Buf) const override;
void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
@@ -139,7 +138,7 @@ public:
uint8_t *PairedLoc = nullptr) const override;
bool isRelRelative(uint32_t Type) const override;
bool isTlsOptimized(unsigned Type, const SymbolBody *S) const override;
- bool isSizeDynReloc(uint32_t Type, const SymbolBody &S) const override;
+ bool isSizeReloc(uint32_t Type) const override;
unsigned relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
uint64_t P, uint64_t SA,
const SymbolBody &S) const override;
@@ -155,6 +154,23 @@ private:
uint64_t SA) const;
};
+class PPCTargetInfo final : public TargetInfo {
+public:
+ PPCTargetInfo();
+ void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
+ void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr) const override;
+ void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const override;
+ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
+ bool relocNeedsPlt(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;
+ bool isRelRelative(uint32_t Type) const override;
+};
+
class PPC64TargetInfo final : public TargetInfo {
public:
PPC64TargetInfo();
@@ -176,13 +192,14 @@ class AArch64TargetInfo final : public TargetInfo {
public:
AArch64TargetInfo();
unsigned getDynReloc(unsigned Type) const override;
- unsigned getPltRefReloc(unsigned Type) const override;
void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
uint64_t PltEntryAddr) const override;
void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
uint64_t PltEntryAddr, int32_t Index,
unsigned RelOff) const override;
+ unsigned getTlsGotReloc(unsigned Type = -1) const override;
+ bool isTlsDynReloc(unsigned Type, const SymbolBody &S) const override;
bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
@@ -191,6 +208,22 @@ public:
uint8_t *PairedLoc = nullptr) const override;
};
+class AMDGPUTargetInfo final : public TargetInfo {
+public:
+ AMDGPUTargetInfo();
+ void writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const override;
+ void writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr) const override;
+ void writePltEntry(uint8_t *Buf, uint64_t GotAddr, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const override;
+ bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
+ bool relocNeedsPlt(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;
+};
+
template <class ELFT> class MipsTargetInfo final : public TargetInfo {
public:
MipsTargetInfo();
@@ -216,6 +249,8 @@ TargetInfo *createTarget() {
return new X86TargetInfo();
case EM_AARCH64:
return new AArch64TargetInfo();
+ case EM_AMDGPU:
+ return new AMDGPUTargetInfo();
case EM_MIPS:
switch (Config->EKind) {
case ELF32LEKind:
@@ -225,6 +260,8 @@ TargetInfo *createTarget() {
default:
error("Unsupported MIPS target");
}
+ case EM_PPC:
+ return new PPCTargetInfo();
case EM_PPC64:
return new PPC64TargetInfo();
case EM_X86_64:
@@ -247,13 +284,9 @@ bool TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
bool TargetInfo::isGotRelative(uint32_t Type) const { return false; }
-unsigned TargetInfo::getPltRefReloc(unsigned Type) const { return PCRelReloc; }
-
bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
-bool TargetInfo::isSizeDynReloc(uint32_t Type, const SymbolBody &S) const {
- return false;
-}
+bool TargetInfo::isSizeReloc(uint32_t Type) const { return false; }
unsigned TargetInfo::relocateTlsOptimize(uint8_t *Loc, uint8_t *BufEnd,
uint32_t Type, uint64_t P, uint64_t SA,
@@ -639,12 +672,6 @@ bool X86_64TargetInfo::isTlsDynReloc(unsigned Type, const SymbolBody &S) const {
return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
}
-unsigned X86_64TargetInfo::getPltRefReloc(unsigned Type) const {
- if (Type == R_X86_64_PLT32)
- return R_X86_64_PC32;
- return Type;
-}
-
bool X86_64TargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
if (needsCopyRel(Type, S))
return false;
@@ -698,16 +725,12 @@ bool X86_64TargetInfo::isRelRelative(uint32_t Type) const {
case R_X86_64_PC32:
case R_X86_64_PC64:
case R_X86_64_PLT32:
- case R_X86_64_SIZE32:
- case R_X86_64_SIZE64:
return true;
}
}
-bool X86_64TargetInfo::isSizeDynReloc(uint32_t Type,
- const SymbolBody &S) const {
- return (Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64) &&
- canBePreempted(&S, false);
+bool X86_64TargetInfo::isSizeReloc(uint32_t Type) const {
+ return Type == R_X86_64_SIZE32 || Type == R_X86_64_SIZE64;
}
bool X86_64TargetInfo::isTlsOptimized(unsigned Type,
@@ -909,6 +932,37 @@ static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; }
static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; }
static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; }
+PPCTargetInfo::PPCTargetInfo() {}
+void PPCTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {}
+void PPCTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr) const {}
+void PPCTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
+ uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {}
+bool PPCTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
+ return false;
+}
+bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
+ return false;
+}
+bool PPCTargetInfo::isRelRelative(uint32_t Type) const { return false; }
+
+void PPCTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
+ uint64_t P, uint64_t SA, uint64_t ZA,
+ uint8_t *PairedLoc) const {
+ switch (Type) {
+ case R_PPC_ADDR16_HA:
+ write16be(Loc, applyPPCHa(SA));
+ break;
+ case R_PPC_ADDR16_LO:
+ write16be(Loc, applyPPCLo(SA));
+ break;
+ default:
+ error("unrecognized reloc " + Twine(Type));
+ }
+}
+
PPC64TargetInfo::PPC64TargetInfo() {
PCRelReloc = R_PPC64_REL24;
GotReloc = R_PPC64_GLOB_DAT;
@@ -1124,8 +1178,10 @@ void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
AArch64TargetInfo::AArch64TargetInfo() {
CopyReloc = R_AARCH64_COPY;
+ IRelativeReloc = R_AARCH64_IRELATIVE;
GotReloc = R_AARCH64_GLOB_DAT;
PltReloc = R_AARCH64_JUMP_SLOT;
+ TlsGotReloc = R_AARCH64_TLS_TPREL64;
LazyRelocations = true;
PltEntrySize = 16;
PltZeroEntrySize = 32;
@@ -1139,8 +1195,6 @@ unsigned AArch64TargetInfo::getDynReloc(unsigned Type) const {
"recompile with -fPIC.");
}
-unsigned AArch64TargetInfo::getPltRefReloc(unsigned Type) const { return Type; }
-
void AArch64TargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
write64le(Buf, Out<ELF64LE>::Plt->getVA());
}
@@ -1187,6 +1241,19 @@ void AArch64TargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
GotEntryAddr);
}
+unsigned AArch64TargetInfo::getTlsGotReloc(unsigned Type) const {
+ if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
+ Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC)
+ return Type;
+ return TlsGotReloc;
+}
+
+bool AArch64TargetInfo::isTlsDynReloc(unsigned Type,
+ const SymbolBody &S) const {
+ return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
+ Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC;
+}
+
bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
if (Config->Shared)
return false;
@@ -1210,17 +1277,28 @@ bool AArch64TargetInfo::needsCopyRel(uint32_t Type, const SymbolBody &S) const {
bool AArch64TargetInfo::relocNeedsGot(uint32_t Type,
const SymbolBody &S) const {
- return Type == R_AARCH64_ADR_GOT_PAGE || Type == R_AARCH64_LD64_GOT_LO12_NC ||
- relocNeedsPlt(Type, S);
+ switch (Type) {
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
+ case R_AARCH64_ADR_GOT_PAGE:
+ case R_AARCH64_LD64_GOT_LO12_NC:
+ return true;
+ default:
+ return relocNeedsPlt(Type, S);
+ }
}
bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type,
const SymbolBody &S) const {
+ if (isGnuIFunc<ELF64LE>(S))
+ return true;
switch (Type) {
default:
return false;
case R_AARCH64_CALL26:
+ case R_AARCH64_CONDBR19:
case R_AARCH64_JUMP26:
+ case R_AARCH64_TSTBR14:
return canBePreempted(&S, true);
}
}
@@ -1273,7 +1351,8 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
updateAArch64Adr(Loc, X & 0x1FFFFF);
break;
}
- case R_AARCH64_ADR_PREL_PG_HI21: {
+ case R_AARCH64_ADR_PREL_PG_HI21:
+ case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: {
uint64_t X = getAArch64Page(SA) - getAArch64Page(P);
checkInt<33>(X, Type);
updateAArch64Adr(Loc, (X >> 12) & 0x1FFFFF); // X[32:12]
@@ -1286,7 +1365,14 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
or32le(Loc, (X & 0x0FFFFFFC) >> 2);
break;
}
+ case R_AARCH64_CONDBR19: {
+ uint64_t X = SA - P;
+ checkInt<21>(X, Type);
+ or32le(Loc, (X & 0x1FFFFC) << 3);
+ break;
+ }
case R_AARCH64_LD64_GOT_LO12_NC:
+ case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
checkAlignment<8>(SA, Type);
or32le(Loc, (SA & 0xFF8) << 7);
break;
@@ -1310,11 +1396,53 @@ void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd,
case R_AARCH64_PREL64:
write64le(Loc, SA - P);
break;
+ case R_AARCH64_TSTBR14: {
+ uint64_t X = SA - P;
+ checkInt<16>(X, Type);
+ or32le(Loc, (X & 0xFFFC) << 3);
+ break;
+ }
default:
error("unrecognized reloc " + Twine(Type));
}
}
+AMDGPUTargetInfo::AMDGPUTargetInfo() {}
+
+void AMDGPUTargetInfo::writeGotPltEntry(uint8_t *Buf, uint64_t Plt) const {
+ llvm_unreachable("not implemented");
+}
+
+void AMDGPUTargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr) const {
+ llvm_unreachable("not implemented");
+}
+
+void AMDGPUTargetInfo::writePltEntry(uint8_t *Buf, uint64_t GotAddr,
+ uint64_t GotEntryAddr,
+ uint64_t PltEntryAddr, int32_t Index,
+ unsigned RelOff) const {
+ llvm_unreachable("not implemented");
+}
+
+bool AMDGPUTargetInfo::relocNeedsGot(uint32_t Type, const SymbolBody &S) const {
+ return false;
+}
+
+bool AMDGPUTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
+ return false;
+}
+
+// Implementing relocations for AMDGPU is low priority since most
+// programs don't use relocations now. Thus, this function is not
+// actually called (relocateOne is called for each relocation).
+// That's why the AMDGPU port works without implementing this function.
+void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
+ uint64_t P, uint64_t SA, uint64_t ZA,
+ uint8_t *PairedLoc) const {
+ llvm_unreachable("not implemented");
+}
+
template <class ELFT> MipsTargetInfo<ELFT>::MipsTargetInfo() {
PageSize = 65536;
GotHeaderEntriesNum = 2;