summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp')
-rw-r--r--lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp355
1 files changed, 303 insertions, 52 deletions
diff --git a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp
index 0e87fb579d4..cb4502030b8 100644
--- a/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp
+++ b/lld/lib/ReaderWriter/MachO/ReferenceKinds.cpp
@@ -9,7 +9,7 @@
#include "ReferenceKinds.h"
-
+#include "MachONormalizedFileBinaryUtils.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -18,6 +18,7 @@
#include "llvm/Support/ErrorHandling.h"
using namespace llvm::MachO;
+using namespace lld::mach_o::normalized;
namespace lld {
namespace mach_o {
@@ -48,6 +49,64 @@ KindHandler::create(MachOLinkingContext::Arch arch) {
}
}
+KindHandler::RelocPattern KindHandler::relocPattern(const Relocation &reloc) {
+ assert((reloc.type & 0xFFF0) == 0);
+ uint16_t result = reloc.type;
+ if (reloc.scattered)
+ result |= rScattered;
+ if (reloc.pcRel)
+ result |= rPcRel;
+ if (reloc.isExtern)
+ result |= rExtern;
+ switch(reloc.length) {
+ case 0:
+ break;
+ case 1:
+ result |= rLength2;
+ break;
+ case 2:
+ result |= rLength4;
+ break;
+ case 3:
+ result |= rLength8;
+ break;
+ default:
+ llvm_unreachable("bad r_length");
+ }
+ return result;
+}
+
+bool KindHandler::isPairedReloc(const Relocation &reloc) {
+ llvm_unreachable("abstract");
+}
+
+std::error_code
+KindHandler::getReferenceInfo(const Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ llvm_unreachable("abstract");
+}
+
+std::error_code
+KindHandler::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ llvm_unreachable("abstract");
+}
+
//===----------------------------------------------------------------------===//
// KindHandler_x86_64
//===----------------------------------------------------------------------===//
@@ -56,38 +115,226 @@ KindHandler_x86_64::~KindHandler_x86_64() {
}
const Registry::KindStrings KindHandler_x86_64::kindStrings[] = {
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_UNSIGNED),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_BRANCH),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_1),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_2),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_SIGNED_4),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT_LOAD),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_GOT),
- LLD_KIND_STRING_ENTRY(X86_64_RELOC_TLV),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_TLV_NOW_LEA),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_TARGET),
- LLD_KIND_STRING_ENTRY(LLD_X86_64_RELOC_LAZY_IMMEDIATE),
+ LLD_KIND_STRING_ENTRY(invalid),
+ LLD_KIND_STRING_ENTRY(branch32),
+ LLD_KIND_STRING_ENTRY(ripRel32),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus1),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus2),
+ LLD_KIND_STRING_ENTRY(ripRel32Minus4),
+ LLD_KIND_STRING_ENTRY(ripRel32Anon),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoad),
+ LLD_KIND_STRING_ENTRY(ripRel32GotLoadNowLea),
+ LLD_KIND_STRING_ENTRY(ripRel32Got),
+ LLD_KIND_STRING_ENTRY(lazyPointer),
+ LLD_KIND_STRING_ENTRY(lazyImmediateLocation),
+ LLD_KIND_STRING_ENTRY(pointer64),
+ LLD_KIND_STRING_ENTRY(pointer64Anon),
+ LLD_KIND_STRING_ENTRY(delta32),
+ LLD_KIND_STRING_ENTRY(delta64),
+ LLD_KIND_STRING_ENTRY(delta32Anon),
+ LLD_KIND_STRING_ENTRY(delta64Anon),
LLD_KIND_STRING_END
};
-
+
bool KindHandler_x86_64::isCallSite(const Reference &ref) {
- return (ref.kindValue() == X86_64_RELOC_BRANCH);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == branch32);
}
bool KindHandler_x86_64::isPointer(const Reference &ref) {
- return (ref.kindValue() == X86_64_RELOC_UNSIGNED);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == pointer64);
}
bool KindHandler_x86_64::isLazyImmediate(const Reference &ref) {
- return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_IMMEDIATE);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == lazyImmediateLocation);
}
bool KindHandler_x86_64::isLazyTarget(const Reference &ref) {
- return (ref.kindValue() == LLD_X86_64_RELOC_LAZY_TARGET);
+ if (ref.kindNamespace() != Reference::KindNamespace::mach_o)
+ return false;
+ assert(ref.kindArch() == Reference::KindArch::x86_64);
+ return (ref.kindValue() == lazyPointer);
+}
+
+bool KindHandler_x86_64::isPairedReloc(const Relocation &reloc) {
+ return (reloc.type == X86_64_RELOC_SUBTRACTOR);
+}
+
+static int32_t readS32(bool swap, const uint8_t *addr) {
+ return read32(swap, *reinterpret_cast<const uint32_t*>(addr));
}
+static int64_t readS64(bool swap, const uint8_t *addr) {
+ return read64(swap, *reinterpret_cast<const uint64_t*>(addr));
+}
+
+Reference::KindValue
+KindHandler_x86_64::kindFromReloc(const Relocation &reloc) {
+ switch(relocPattern(reloc)) {
+ case X86_64_RELOC_BRANCH | rPcRel | rExtern | rLength4:
+ return branch32;
+ case X86_64_RELOC_SIGNED | rPcRel | rExtern | rLength4:
+ return ripRel32;
+ case X86_64_RELOC_SIGNED | rPcRel | rLength4:
+ return ripRel32Anon;
+ case X86_64_RELOC_SIGNED_1 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus1;
+ case X86_64_RELOC_SIGNED_2 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus2;
+ case X86_64_RELOC_SIGNED_4 | rPcRel | rExtern | rLength4:
+ return ripRel32Minus4;
+ case X86_64_RELOC_GOT_LOAD | rPcRel | rExtern | rLength4:
+ return ripRel32GotLoad;
+ case X86_64_RELOC_GOT | rPcRel | rExtern | rLength4:
+ return ripRel32Got;
+ case X86_64_RELOC_UNSIGNED | rExtern | rLength8:
+ return pointer64;
+ case X86_64_RELOC_UNSIGNED | rLength8:
+ return pointer64Anon;
+ default:
+ return invalid;
+ }
+
+}
+
+
+std::error_code
+KindHandler_x86_64::getReferenceInfo(const Relocation &reloc,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ typedef std::error_code E;
+ *kind = kindFromReloc(reloc);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown type"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ uint64_t targetAddress;
+ switch (*kind) {
+ case branch32:
+ case ripRel32:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent);
+ return std::error_code();
+ case ripRel32Minus1:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 1;
+ return std::error_code();
+ case ripRel32Minus2:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 2;
+ return std::error_code();
+ case ripRel32Minus4:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + 4;
+ return std::error_code();
+ case ripRel32Anon:
+ targetAddress = fixupAddress + 4 + readS32(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ case ripRel32GotLoad:
+ case ripRel32Got:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = 0;
+ return std::error_code();
+ case pointer64:
+ if (E ec = atomFromSymbolIndex(reloc.symbol, target))
+ return ec;
+ *addend = readS64(swap, fixupContent);
+ return std::error_code();
+ case pointer64Anon:
+ targetAddress = readS64(swap, fixupContent);
+ return atomFromAddress(reloc.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc kind");
+ }
+}
+
+
+Reference::KindValue
+KindHandler_x86_64::kindFromRelocPair(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2) {
+ switch(relocPattern(reloc1) << 16 | relocPattern(reloc2)) {
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength8):
+ return delta64;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rExtern | rLength4):
+ return delta32;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength8) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength8):
+ return delta64Anon;
+ case ((X86_64_RELOC_SUBTRACTOR | rExtern | rLength4) << 16 |
+ X86_64_RELOC_UNSIGNED | rLength4):
+ return delta32Anon;
+ default:
+ llvm_unreachable("bad reloc pairs");
+ }
+}
+
+
+std::error_code
+KindHandler_x86_64::getPairReferenceInfo(const normalized::Relocation &reloc1,
+ const normalized::Relocation &reloc2,
+ const DefinedAtom *inAtom,
+ uint32_t offsetInAtom,
+ uint64_t fixupAddress, bool swap,
+ FindAtomBySectionAndAddress atomFromAddress,
+ FindAtomBySymbolIndex atomFromSymbolIndex,
+ Reference::KindValue *kind,
+ const lld::Atom **target,
+ Reference::Addend *addend) {
+ *kind = kindFromRelocPair(reloc1, reloc2);
+ if (*kind == invalid)
+ return make_dynamic_error_code(Twine("unknown pair"));
+ const uint8_t *fixupContent = &inAtom->rawContent()[offsetInAtom];
+ typedef std::error_code E;
+ uint64_t targetAddress;
+ const lld::Atom *fromTarget;
+ if (E ec = atomFromSymbolIndex(reloc1.symbol, &fromTarget))
+ return ec;
+ if (fromTarget != inAtom)
+ return make_dynamic_error_code(Twine("pointer diff not in base atom"));
+ switch (*kind) {
+ case delta64:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = readS64(swap, fixupContent) + offsetInAtom;
+ return std::error_code();
+ case delta32:
+ if (E ec = atomFromSymbolIndex(reloc2.symbol, target))
+ return ec;
+ *addend = readS32(swap, fixupContent) + offsetInAtom;
+ return std::error_code();
+ case delta64Anon:
+ targetAddress = offsetInAtom + readS64(swap, fixupContent);
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ case delta32Anon:
+ targetAddress = offsetInAtom + readS32(swap, fixupContent);
+ return atomFromAddress(reloc2.symbol, targetAddress, target, addend);
+ default:
+ llvm_unreachable("bad reloc pair kind");
+ }
+}
+
+
+
void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns,
Reference::KindArch arch,
Reference::KindValue kindValue,
@@ -100,39 +347,43 @@ void KindHandler_x86_64::applyFixup(Reference::KindNamespace ns,
int32_t *loc32 = reinterpret_cast<int32_t*>(location);
uint64_t* loc64 = reinterpret_cast<uint64_t*>(location);
switch (kindValue) {
- case X86_64_RELOC_BRANCH:
- case X86_64_RELOC_SIGNED:
- case X86_64_RELOC_GOT_LOAD:
- case X86_64_RELOC_GOT:
- case X86_64_RELOC_TLV:
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case X86_64_RELOC_UNSIGNED:
- *loc64 = targetAddress + addend;
- break;
- case X86_64_RELOC_SIGNED_1:
- *loc32 = (targetAddress - (fixupAddress+5)) + addend;
- break;
- case X86_64_RELOC_SIGNED_2:
- *loc32 = (targetAddress - (fixupAddress+6)) + addend;
- break;
- case X86_64_RELOC_SIGNED_4:
- *loc32 = (targetAddress - (fixupAddress+8)) + addend;
- break;
- case LLD_X86_64_RELOC_SIGNED_32:
- *loc32 = (targetAddress - fixupAddress) + addend;
- break;
- case LLD_X86_64_RELOC_GOT_LOAD_NOW_LEA:
- case LLD_X86_64_RELOC_TLV_NOW_LEA:
- // Change MOVQ to LEA
- assert(location[-2] == 0x8B);
- location[-2] = 0x8D;
- *loc32 = (targetAddress - (fixupAddress+4)) + addend;
- break;
- case LLD_X86_64_RELOC_LAZY_TARGET:
- case LLD_X86_64_RELOC_LAZY_IMMEDIATE:
- // do nothing
- break;
+ case branch32:
+ case ripRel32:
+ case ripRel32Got:
+ case ripRel32GotLoad:
+ *loc32 = (targetAddress - (fixupAddress+4)) + addend;
+ break;
+ case pointer64:
+ case pointer64Anon:
+ *loc64 = targetAddress + addend;
+ break;
+ case ripRel32Minus1:
+ *loc32 = (targetAddress - (fixupAddress+5)) + addend;
+ break;
+ case ripRel32Minus2:
+ *loc32 = (targetAddress - (fixupAddress+6)) + addend;
+ break;
+ case ripRel32Minus4:
+ *loc32 = (targetAddress - (fixupAddress+8)) + addend;
+ break;
+ case delta32:
+ case delta32Anon:
+ *loc32 = (targetAddress - fixupAddress) + addend;
+ break;
+ case delta64:
+ case delta64Anon:
+ *loc64 = (targetAddress - fixupAddress) + addend;
+ break;
+ case ripRel32GotLoadNowLea:
+ // Change MOVQ to LEA
+ assert(location[-2] == 0x8B);
+ location[-2] = 0x8D;
+ *loc32 = (targetAddress - (fixupAddress+4)) + addend;
+ break;
+ case lazyPointer:
+ case lazyImmediateLocation:
+ // do nothing
+ break;
default:
llvm_unreachable("invalid x86_64 Reference Kind");
break;
OpenPOWER on IntegriCloud