summaryrefslogtreecommitdiff
path: root/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h')
-rw-r--r--lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h103
1 files changed, 89 insertions, 14 deletions
diff --git a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
index 97cbc153b227..2a619c549cfa 100644
--- a/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
+++ b/lib/ExecutionEngine/RuntimeDyld/Targets/RuntimeDyldMachOAArch64.h
@@ -32,18 +32,37 @@ public:
unsigned getStubAlignment() override { return 8; }
/// Extract the addend encoded in the instruction / memory location.
- int64_t decodeAddend(const RelocationEntry &RE) const {
+ Expected<int64_t> decodeAddend(const RelocationEntry &RE) const {
const SectionEntry &Section = Sections[RE.SectionID];
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
unsigned NumBytes = 1 << RE.Size;
int64_t Addend = 0;
// Verify that the relocation has the correct size and alignment.
switch (RE.RelType) {
- default:
- llvm_unreachable("Unsupported relocation type!");
- case MachO::ARM64_RELOC_UNSIGNED:
- assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
+ default: {
+ std::string ErrMsg;
+ {
+ raw_string_ostream ErrStream(ErrMsg);
+ ErrStream << "Unsupported relocation type: "
+ << getRelocName(RE.RelType);
+ }
+ return make_error<StringError>(std::move(ErrMsg),
+ inconvertibleErrorCode());
+ }
+ case MachO::ARM64_RELOC_POINTER_TO_GOT:
+ case MachO::ARM64_RELOC_UNSIGNED: {
+ if (NumBytes != 4 && NumBytes != 8) {
+ std::string ErrMsg;
+ {
+ raw_string_ostream ErrStream(ErrMsg);
+ ErrStream << "Invalid relocation size for relocation "
+ << getRelocName(RE.RelType);
+ }
+ return make_error<StringError>(std::move(ErrMsg),
+ inconvertibleErrorCode());
+ }
break;
+ }
case MachO::ARM64_RELOC_BRANCH26:
case MachO::ARM64_RELOC_PAGE21:
case MachO::ARM64_RELOC_PAGEOFF12:
@@ -58,6 +77,7 @@ public:
switch (RE.RelType) {
default:
llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_POINTER_TO_GOT:
case MachO::ARM64_RELOC_UNSIGNED:
// This could be an unaligned memory location.
if (NumBytes == 4)
@@ -66,9 +86,11 @@ public:
Addend = *reinterpret_cast<support::ulittle64_t *>(LocalAddress);
break;
case MachO::ARM64_RELOC_BRANCH26: {
- // Verify that the relocation points to the expected branch instruction.
+ // Verify that the relocation points to a B/BL instruction.
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
- assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction.");
+ assert(((*p & 0xFC000000) == 0x14000000 ||
+ (*p & 0xFC000000) == 0x94000000) &&
+ "Expected branch instruction.");
// Get the 26 bit addend encoded in the branch instruction and sign-extend
// to 64 bit. The lower 2 bits are always zeros and are therefore implicit
@@ -137,6 +159,7 @@ public:
switch (RelType) {
default:
llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_POINTER_TO_GOT:
case MachO::ARM64_RELOC_UNSIGNED:
assert((NumBytes == 4 || NumBytes == 8) && "Invalid relocation size.");
break;
@@ -154,6 +177,7 @@ public:
switch (RelType) {
default:
llvm_unreachable("Unsupported relocation type!");
+ case MachO::ARM64_RELOC_POINTER_TO_GOT:
case MachO::ARM64_RELOC_UNSIGNED:
// This could be an unaligned memory location.
if (NumBytes == 4)
@@ -164,7 +188,9 @@ public:
case MachO::ARM64_RELOC_BRANCH26: {
auto *p = reinterpret_cast<support::aligned_ulittle32_t *>(LocalAddress);
// Verify that the relocation points to the expected branch instruction.
- assert((*p & 0xFC000000) == 0x14000000 && "Expected branch instruction.");
+ assert(((*p & 0xFC000000) == 0x14000000 ||
+ (*p & 0xFC000000) == 0x94000000) &&
+ "Expected branch instruction.");
// Verify addend value.
assert((Addend & 0x3) == 0 && "Branch target is not aligned");
@@ -278,7 +304,20 @@ public:
return processSubtractRelocation(SectionID, RelI, Obj, ObjSectionToID);
RelocationEntry RE(getRelocationEntry(SectionID, Obj, RelI));
- RE.Addend = decodeAddend(RE);
+
+ if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
+ bool Valid =
+ (RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel);
+ if (!Valid)
+ return make_error<StringError>("ARM64_RELOC_POINTER_TO_GOT supports "
+ "32-bit pc-rel or 64-bit absolute only",
+ inconvertibleErrorCode());
+ }
+
+ if (auto Addend = decodeAddend(RE))
+ RE.Addend = *Addend;
+ else
+ return Addend.takeError();
assert((ExplicitAddend == 0 || RE.Addend == 0) && "Relocation has "\
"ARM64_RELOC_ADDEND and embedded addend in the instruction.");
@@ -292,13 +331,17 @@ public:
return ValueOrErr.takeError();
bool IsExtern = Obj.getPlainRelocationExternal(RelInfo);
- if (!IsExtern && RE.IsPCRel)
+ if (RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT) {
+ // We'll take care of the offset in processGOTRelocation.
+ Value.Offset = 0;
+ } else if (!IsExtern && RE.IsPCRel)
makeValueAddendPCRel(Value, RelI, 1 << RE.Size);
RE.Addend = Value.Offset;
if (RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGE21 ||
- RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12)
+ RE.RelType == MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12 ||
+ RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT)
processGOTRelocation(RE, Value, Stubs);
else {
if (Value.SymbolName)
@@ -311,7 +354,7 @@ public:
}
void resolveRelocation(const RelocationEntry &RE, uint64_t Value) override {
- DEBUG(dumpRelocationToResolve(RE, Value));
+ LLVM_DEBUG(dumpRelocationToResolve(RE, Value));
const SectionEntry &Section = Sections[RE.SectionID];
uint8_t *LocalAddress = Section.getAddressWithOffset(RE.Offset);
@@ -331,6 +374,19 @@ public:
encodeAddend(LocalAddress, 1 << RE.Size, RelType, Value + RE.Addend);
break;
}
+
+ case MachO::ARM64_RELOC_POINTER_TO_GOT: {
+ assert(((RE.Size == 2 && RE.IsPCRel) || (RE.Size == 3 && !RE.IsPCRel)) &&
+ "ARM64_RELOC_POINTER_TO_GOT only supports 32-bit pc-rel or 64-bit "
+ "absolute");
+ // Addend is the GOT entry address and RE.Offset the target of the
+ // relocation.
+ uint64_t Result =
+ RE.IsPCRel ? (RE.Addend - RE.Offset) : (Value + RE.Addend);
+ encodeAddend(LocalAddress, 1 << RE.Size, RelType, Result);
+ break;
+ }
+
case MachO::ARM64_RELOC_BRANCH26: {
assert(RE.IsPCRel && "not PCRel and ARM64_RELOC_BRANCH26 not supported");
// Check if branch is in range.
@@ -368,7 +424,7 @@ public:
writeBytesUnaligned(Value, LocalAddress, 1 << RE.Size);
break;
}
- case MachO::ARM64_RELOC_POINTER_TO_GOT:
+
case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21:
case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
llvm_unreachable("Relocation type not yet implemented!");
@@ -386,7 +442,9 @@ public:
private:
void processGOTRelocation(const RelocationEntry &RE,
RelocationValueRef &Value, StubMap &Stubs) {
- assert(RE.Size == 2);
+ assert((RE.RelType == MachO::ARM64_RELOC_POINTER_TO_GOT &&
+ (RE.Size == 2 || RE.Size == 3)) ||
+ RE.Size == 2);
SectionEntry &Section = Sections[RE.SectionID];
StubMap::const_iterator i = Stubs.find(Value);
int64_t Offset;
@@ -459,6 +517,23 @@ private:
return ++RelI;
}
+ static const char *getRelocName(uint32_t RelocType) {
+ switch (RelocType) {
+ case MachO::ARM64_RELOC_UNSIGNED: return "ARM64_RELOC_UNSIGNED";
+ case MachO::ARM64_RELOC_SUBTRACTOR: return "ARM64_RELOC_SUBTRACTOR";
+ case MachO::ARM64_RELOC_BRANCH26: return "ARM64_RELOC_BRANCH26";
+ case MachO::ARM64_RELOC_PAGE21: return "ARM64_RELOC_PAGE21";
+ case MachO::ARM64_RELOC_PAGEOFF12: return "ARM64_RELOC_PAGEOFF12";
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGE21: return "ARM64_RELOC_GOT_LOAD_PAGE21";
+ case MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12: return "ARM64_RELOC_GOT_LOAD_PAGEOFF12";
+ case MachO::ARM64_RELOC_POINTER_TO_GOT: return "ARM64_RELOC_POINTER_TO_GOT";
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGE21: return "ARM64_RELOC_TLVP_LOAD_PAGE21";
+ case MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12: return "ARM64_RELOC_TLVP_LOAD_PAGEOFF12";
+ case MachO::ARM64_RELOC_ADDEND: return "ARM64_RELOC_ADDEND";
+ }
+ return "Unrecognized arm64 addend";
+ }
+
};
}