aboutsummaryrefslogtreecommitdiff
path: root/lld/MachO/Arch
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
committerDimitry Andric <dim@FreeBSD.org>2022-07-03 14:10:23 +0000
commit145449b1e420787bb99721a429341fa6be3adfb6 (patch)
tree1d56ae694a6de602e348dd80165cf881a36600ed /lld/MachO/Arch
parentecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff)
Diffstat (limited to 'lld/MachO/Arch')
-rw-r--r--lld/MachO/Arch/ARM.cpp4
-rw-r--r--lld/MachO/Arch/ARM64.cpp322
-rw-r--r--lld/MachO/Arch/ARM64Common.cpp41
-rw-r--r--lld/MachO/Arch/ARM64Common.h59
-rw-r--r--lld/MachO/Arch/ARM64_32.cpp8
-rw-r--r--lld/MachO/Arch/X86_64.cpp15
6 files changed, 392 insertions, 57 deletions
diff --git a/lld/MachO/Arch/ARM.cpp b/lld/MachO/Arch/ARM.cpp
index 4dda94d7b0f3..7de0837fcf38 100644
--- a/lld/MachO/Arch/ARM.cpp
+++ b/lld/MachO/Arch/ARM.cpp
@@ -34,7 +34,7 @@ struct ARM : TargetInfo {
void writeStub(uint8_t *buf, const Symbol &) const override;
void writeStubHelperHeader(uint8_t *buf) const override;
- void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
+ void writeStubHelperEntry(uint8_t *buf, const Symbol &,
uint64_t entryAddr) const override;
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
@@ -148,7 +148,7 @@ void ARM::writeStubHelperHeader(uint8_t *buf) const {
fatal("TODO: implement this");
}
-void ARM::writeStubHelperEntry(uint8_t *buf, const DylibSymbol &sym,
+void ARM::writeStubHelperEntry(uint8_t *buf, const Symbol &sym,
uint64_t entryAddr) const {
fatal("TODO: implement this");
}
diff --git a/lld/MachO/Arch/ARM64.cpp b/lld/MachO/Arch/ARM64.cpp
index 001e112ae3ad..7064df5793aa 100644
--- a/lld/MachO/Arch/ARM64.cpp
+++ b/lld/MachO/Arch/ARM64.cpp
@@ -13,6 +13,7 @@
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
+#include "mach-o/compact_unwind_encoding.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/BinaryFormat/MachO.h"
@@ -31,10 +32,12 @@ struct ARM64 : ARM64Common {
ARM64();
void writeStub(uint8_t *buf, const Symbol &) const override;
void writeStubHelperHeader(uint8_t *buf) const override;
- void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
+ void writeStubHelperEntry(uint8_t *buf, const Symbol &,
uint64_t entryAddr) const override;
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
void populateThunk(InputSection *thunk, Symbol *funcSym) override;
+ void applyOptimizationHints(uint8_t *, const ConcatInputSection *,
+ ArrayRef<uint64_t>) const override;
};
} // namespace
@@ -100,7 +103,7 @@ static constexpr uint32_t stubHelperEntryCode[] = {
0x00000000, // 08: l0: .long 0
};
-void ARM64::writeStubHelperEntry(uint8_t *buf8, const DylibSymbol &sym,
+void ARM64::writeStubHelperEntry(uint8_t *buf8, const Symbol &sym,
uint64_t entryVA) const {
::writeStubHelperEntry(buf8, stubHelperEntryCode, sym, entryVA);
}
@@ -141,10 +144,325 @@ ARM64::ARM64() : ARM64Common(LP64()) {
backwardBranchRange = 128 * 1024 * 1024;
forwardBranchRange = backwardBranchRange - 4;
+ modeDwarfEncoding = UNWIND_ARM64_MODE_DWARF;
+ subtractorRelocType = ARM64_RELOC_SUBTRACTOR;
+ unsignedRelocType = ARM64_RELOC_UNSIGNED;
+
stubHelperHeaderSize = sizeof(stubHelperHeaderCode);
stubHelperEntrySize = sizeof(stubHelperEntryCode);
}
+namespace {
+struct Adrp {
+ uint32_t destRegister;
+};
+
+struct Add {
+ uint8_t destRegister;
+ uint8_t srcRegister;
+ uint32_t addend;
+};
+
+enum ExtendType { ZeroExtend = 1, Sign64 = 2, Sign32 = 3 };
+
+struct Ldr {
+ uint8_t destRegister;
+ uint8_t baseRegister;
+ uint8_t size;
+ bool isFloat;
+ ExtendType extendType;
+ uint64_t offset;
+};
+
+struct PerformedReloc {
+ const Reloc &rel;
+ uint64_t referentVA;
+};
+
+class OptimizationHintContext {
+public:
+ OptimizationHintContext(uint8_t *buf, const ConcatInputSection *isec,
+ ArrayRef<uint64_t> relocTargets)
+ : buf(buf), isec(isec), relocTargets(relocTargets),
+ relocIt(isec->relocs.rbegin()) {}
+
+ void applyAdrpAdd(const OptimizationHint &);
+ void applyAdrpAdrp(const OptimizationHint &);
+ void applyAdrpLdr(const OptimizationHint &);
+
+private:
+ uint8_t *buf;
+ const ConcatInputSection *isec;
+ ArrayRef<uint64_t> relocTargets;
+ std::vector<Reloc>::const_reverse_iterator relocIt;
+
+ uint64_t getRelocTarget(const Reloc &);
+
+ Optional<PerformedReloc> findPrimaryReloc(uint64_t offset);
+ Optional<PerformedReloc> findReloc(uint64_t offset);
+};
+} // namespace
+
+static bool parseAdrp(uint32_t insn, Adrp &adrp) {
+ if ((insn & 0x9f000000) != 0x90000000)
+ return false;
+ adrp.destRegister = insn & 0x1f;
+ return true;
+}
+
+static bool parseAdd(uint32_t insn, Add &add) {
+ if ((insn & 0xffc00000) != 0x91000000)
+ return false;
+ add.destRegister = insn & 0x1f;
+ add.srcRegister = (insn >> 5) & 0x1f;
+ add.addend = (insn >> 10) & 0xfff;
+ return true;
+}
+
+static bool parseLdr(uint32_t insn, Ldr &ldr) {
+ ldr.destRegister = insn & 0x1f;
+ ldr.baseRegister = (insn >> 5) & 0x1f;
+ uint8_t size = insn >> 30;
+ uint8_t opc = (insn >> 22) & 3;
+
+ if ((insn & 0x3fc00000) == 0x39400000) {
+ // LDR (immediate), LDRB (immediate), LDRH (immediate)
+ ldr.size = 1 << size;
+ ldr.extendType = ZeroExtend;
+ ldr.isFloat = false;
+ } else if ((insn & 0x3f800000) == 0x39800000) {
+ // LDRSB (immediate), LDRSH (immediate), LDRSW (immediate)
+ ldr.size = 1 << size;
+ ldr.extendType = static_cast<ExtendType>(opc);
+ ldr.isFloat = false;
+ } else if ((insn & 0x3f400000) == 0x3d400000) {
+ // LDR (immediate, SIMD&FP)
+ ldr.extendType = ZeroExtend;
+ ldr.isFloat = true;
+ if (size == 2 && opc == 1)
+ ldr.size = 4;
+ else if (size == 3 && opc == 1)
+ ldr.size = 8;
+ else if (size == 0 && opc == 3)
+ ldr.size = 16;
+ else
+ return false;
+ } else {
+ return false;
+ }
+ ldr.offset = ((insn >> 10) & 0xfff) * ldr.size;
+ return true;
+}
+
+static void writeAdr(void *loc, uint32_t dest, int32_t delta) {
+ uint32_t opcode = 0x10000000;
+ uint32_t immHi = (delta & 0x001ffffc) << 3;
+ uint32_t immLo = (delta & 0x00000003) << 29;
+ write32le(loc, opcode | immHi | immLo | dest);
+}
+
+static void writeNop(void *loc) { write32le(loc, 0xd503201f); }
+
+static void writeLiteralLdr(void *loc, Ldr original, int32_t delta) {
+ uint32_t imm19 = (delta & 0x001ffffc) << 3;
+ uint32_t opcode = 0;
+ switch (original.size) {
+ case 4:
+ if (original.isFloat)
+ opcode = 0x1c000000;
+ else
+ opcode = original.extendType == Sign64 ? 0x98000000 : 0x18000000;
+ break;
+ case 8:
+ opcode = original.isFloat ? 0x5c000000 : 0x58000000;
+ break;
+ case 16:
+ opcode = 0x9c000000;
+ break;
+ default:
+ assert(false && "Invalid size for literal ldr");
+ }
+ write32le(loc, opcode | imm19 | original.destRegister);
+}
+
+uint64_t OptimizationHintContext::getRelocTarget(const Reloc &reloc) {
+ size_t relocIdx = &reloc - isec->relocs.data();
+ return relocTargets[relocIdx];
+}
+
+// Optimization hints are sorted in a monotonically increasing order by their
+// first address as are relocations (albeit in decreasing order), so if we keep
+// a pointer around to the last found relocation, we don't have to do a full
+// binary search every time.
+Optional<PerformedReloc>
+OptimizationHintContext::findPrimaryReloc(uint64_t offset) {
+ const auto end = isec->relocs.rend();
+ while (relocIt != end && relocIt->offset < offset)
+ ++relocIt;
+ if (relocIt == end || relocIt->offset != offset)
+ return None;
+ return PerformedReloc{*relocIt, getRelocTarget(*relocIt)};
+}
+
+// The second and third addresses of optimization hints have no such
+// monotonicity as the first, so we search the entire range of relocations.
+Optional<PerformedReloc> OptimizationHintContext::findReloc(uint64_t offset) {
+ // Optimization hints often apply to successive relocations, so we check for
+ // that first before doing a full binary search.
+ auto end = isec->relocs.rend();
+ if (relocIt < end - 1 && (relocIt + 1)->offset == offset)
+ return PerformedReloc{*(relocIt + 1), getRelocTarget(*(relocIt + 1))};
+
+ auto reloc = lower_bound(isec->relocs, offset,
+ [](const Reloc &reloc, uint64_t offset) {
+ return offset < reloc.offset;
+ });
+
+ if (reloc == isec->relocs.end() || reloc->offset != offset)
+ return None;
+ return PerformedReloc{*reloc, getRelocTarget(*reloc)};
+}
+
+// Transforms a pair of adrp+add instructions into an adr instruction if the
+// target is within the +/- 1 MiB range allowed by the adr's 21 bit signed
+// immediate offset.
+//
+// adrp xN, _foo@PAGE
+// add xM, xN, _foo@PAGEOFF
+// ->
+// adr xM, _foo
+// nop
+void OptimizationHintContext::applyAdrpAdd(const OptimizationHint &hint) {
+ uint32_t ins1 = read32le(buf + hint.offset0);
+ uint32_t ins2 = read32le(buf + hint.offset0 + hint.delta[0]);
+ Adrp adrp;
+ if (!parseAdrp(ins1, adrp))
+ return;
+ Add add;
+ if (!parseAdd(ins2, add))
+ return;
+ if (adrp.destRegister != add.srcRegister)
+ return;
+
+ Optional<PerformedReloc> rel1 = findPrimaryReloc(hint.offset0);
+ Optional<PerformedReloc> rel2 = findReloc(hint.offset0 + hint.delta[0]);
+ if (!rel1 || !rel2)
+ return;
+ if (rel1->referentVA != rel2->referentVA)
+ return;
+ int64_t delta = rel1->referentVA - rel1->rel.offset - isec->getVA();
+ if (delta >= (1 << 20) || delta < -(1 << 20))
+ return;
+
+ writeAdr(buf + hint.offset0, add.destRegister, delta);
+ writeNop(buf + hint.offset0 + hint.delta[0]);
+}
+
+// Transforms two adrp instructions into a single adrp if their referent
+// addresses are located on the same 4096 byte page.
+//
+// adrp xN, _foo@PAGE
+// adrp xN, _bar@PAGE
+// ->
+// adrp xN, _foo@PAGE
+// nop
+void OptimizationHintContext::applyAdrpAdrp(const OptimizationHint &hint) {
+ uint32_t ins1 = read32le(buf + hint.offset0);
+ uint32_t ins2 = read32le(buf + hint.offset0 + hint.delta[0]);
+ Adrp adrp1, adrp2;
+ if (!parseAdrp(ins1, adrp1) || !parseAdrp(ins2, adrp2))
+ return;
+ if (adrp1.destRegister != adrp2.destRegister)
+ return;
+
+ Optional<PerformedReloc> rel1 = findPrimaryReloc(hint.offset0);
+ Optional<PerformedReloc> rel2 = findReloc(hint.offset0 + hint.delta[0]);
+ if (!rel1 || !rel2)
+ return;
+ if ((rel1->referentVA & ~0xfffULL) != (rel2->referentVA & ~0xfffULL))
+ return;
+
+ writeNop(buf + hint.offset0 + hint.delta[0]);
+}
+
+// Transforms a pair of adrp+ldr (immediate) instructions into an ldr (literal)
+// load from a PC-relative address if it is 4-byte aligned and within +/- 1 MiB,
+// as ldr can encode a signed 19-bit offset that gets multiplied by 4.
+//
+// adrp xN, _foo@PAGE
+// ldr xM, [xN, _foo@PAGEOFF]
+// ->
+// nop
+// ldr xM, _foo
+void OptimizationHintContext::applyAdrpLdr(const OptimizationHint &hint) {
+ uint32_t ins1 = read32le(buf + hint.offset0);
+ uint32_t ins2 = read32le(buf + hint.offset0 + hint.delta[0]);
+ Adrp adrp;
+ if (!parseAdrp(ins1, adrp))
+ return;
+ Ldr ldr;
+ if (!parseLdr(ins2, ldr))
+ return;
+ if (adrp.destRegister != ldr.baseRegister)
+ return;
+
+ Optional<PerformedReloc> rel1 = findPrimaryReloc(hint.offset0);
+ Optional<PerformedReloc> rel2 = findReloc(hint.offset0 + hint.delta[0]);
+ if (!rel1 || !rel2)
+ return;
+ if (ldr.offset != (rel1->referentVA & 0xfff))
+ return;
+ if ((rel1->referentVA & 3) != 0)
+ return;
+ if (ldr.size == 1 || ldr.size == 2)
+ return;
+ int64_t delta = rel1->referentVA - rel2->rel.offset - isec->getVA();
+ if (delta >= (1 << 20) || delta < -(1 << 20))
+ return;
+
+ writeNop(buf + hint.offset0);
+ writeLiteralLdr(buf + hint.offset0 + hint.delta[0], ldr, delta);
+}
+
+void ARM64::applyOptimizationHints(uint8_t *buf, const ConcatInputSection *isec,
+ ArrayRef<uint64_t> relocTargets) const {
+ assert(isec);
+ assert(relocTargets.size() == isec->relocs.size());
+
+ // Note: Some of these optimizations might not be valid when shared regions
+ // are in use. Will need to revisit this if splitSegInfo is added.
+
+ OptimizationHintContext ctx1(buf, isec, relocTargets);
+ for (const OptimizationHint &hint : isec->optimizationHints) {
+ switch (hint.type) {
+ case LOH_ARM64_ADRP_ADRP:
+ // This is done in another pass because the other optimization hints
+ // might cause its targets to be turned into NOPs.
+ break;
+ case LOH_ARM64_ADRP_LDR:
+ ctx1.applyAdrpLdr(hint);
+ break;
+ case LOH_ARM64_ADRP_ADD_LDR:
+ case LOH_ARM64_ADRP_LDR_GOT_LDR:
+ case LOH_ARM64_ADRP_ADD_STR:
+ case LOH_ARM64_ADRP_LDR_GOT_STR:
+ // TODO: Implement these
+ break;
+ case LOH_ARM64_ADRP_ADD:
+ ctx1.applyAdrpAdd(hint);
+ break;
+ case LOH_ARM64_ADRP_LDR_GOT:
+ // TODO: Implement this as well
+ break;
+ }
+ }
+
+ OptimizationHintContext ctx2(buf, isec, relocTargets);
+ for (const OptimizationHint &hint : isec->optimizationHints)
+ if (hint.type == LOH_ARM64_ADRP_ADRP)
+ ctx2.applyAdrpAdrp(hint);
+}
+
TargetInfo *macho::createARM64TargetInfo() {
static ARM64 t;
return &t;
diff --git a/lld/MachO/Arch/ARM64Common.cpp b/lld/MachO/Arch/ARM64Common.cpp
index 67e7292fd6fd..f55258ce8ec9 100644
--- a/lld/MachO/Arch/ARM64Common.cpp
+++ b/lld/MachO/Arch/ARM64Common.cpp
@@ -38,56 +38,57 @@ int64_t ARM64Common::getEmbeddedAddend(MemoryBufferRef mb, uint64_t offset,
}
}
+static void writeValue(uint8_t *loc, const Reloc &r, uint64_t value) {
+ switch (r.length) {
+ case 2:
+ checkInt(loc, r, value, 32);
+ write32le(loc, value);
+ break;
+ case 3:
+ write64le(loc, value);
+ break;
+ default:
+ llvm_unreachable("invalid r_length");
+ }
+}
+
// For instruction relocations (load, store, add), the base
// instruction is pre-populated in the text section. A pre-populated
// instruction has opcode & register-operand bits set, with immediate
// operands zeroed. We read it from text, OR-in the immediate
// operands, then write-back the completed instruction.
-
void ARM64Common::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
uint64_t pc) const {
+ auto loc32 = reinterpret_cast<uint32_t *>(loc);
uint32_t base = ((r.length == 2) ? read32le(loc) : 0);
switch (r.type) {
case ARM64_RELOC_BRANCH26:
- value = encodeBranch26(r, base, value - pc);
+ encodeBranch26(loc32, r, base, value - pc);
break;
case ARM64_RELOC_SUBTRACTOR:
case ARM64_RELOC_UNSIGNED:
- if (r.length == 2)
- checkInt(r, value, 32);
+ writeValue(loc, r, value);
break;
case ARM64_RELOC_POINTER_TO_GOT:
if (r.pcrel)
value -= pc;
- checkInt(r, value, 32);
+ writeValue(loc, r, value);
break;
case ARM64_RELOC_PAGE21:
case ARM64_RELOC_GOT_LOAD_PAGE21:
- case ARM64_RELOC_TLVP_LOAD_PAGE21: {
+ case ARM64_RELOC_TLVP_LOAD_PAGE21:
assert(r.pcrel);
- value = encodePage21(r, base, pageBits(value) - pageBits(pc));
+ encodePage21(loc32, r, base, pageBits(value) - pageBits(pc));
break;
- }
case ARM64_RELOC_PAGEOFF12:
case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
assert(!r.pcrel);
- value = encodePageOff12(base, value);
+ encodePageOff12(loc32, base, value);
break;
default:
llvm_unreachable("unexpected relocation type");
}
-
- switch (r.length) {
- case 2:
- write32le(loc, value);
- break;
- case 3:
- write64le(loc, value);
- break;
- default:
- llvm_unreachable("invalid r_length");
- }
}
void ARM64Common::relaxGotLoad(uint8_t *loc, uint8_t type) const {
diff --git a/lld/MachO/Arch/ARM64Common.h b/lld/MachO/Arch/ARM64Common.h
index 934101caefb9..54f94ee76c06 100644
--- a/lld/MachO/Arch/ARM64Common.h
+++ b/lld/MachO/Arch/ARM64Common.h
@@ -40,16 +40,18 @@ inline uint64_t bitField(uint64_t value, int right, int width, int left) {
// | | imm26 |
// +-----------+---------------------------------------------------+
-inline uint64_t encodeBranch26(const Reloc &r, uint64_t base, uint64_t va) {
- checkInt(r, va, 28);
+inline void encodeBranch26(uint32_t *loc, const Reloc &r, uint32_t base,
+ uint64_t va) {
+ checkInt(loc, r, va, 28);
// Since branch destinations are 4-byte aligned, the 2 least-
// significant bits are 0. They are right shifted off the end.
- return (base | bitField(va, 2, 26, 0));
+ llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0));
}
-inline uint64_t encodeBranch26(SymbolDiagnostic d, uint64_t base, uint64_t va) {
- checkInt(d, va, 28);
- return (base | bitField(va, 2, 26, 0));
+inline void encodeBranch26(uint32_t *loc, SymbolDiagnostic d, uint32_t base,
+ uint64_t va) {
+ checkInt(loc, d, va, 28);
+ llvm::support::endian::write32le(loc, base | bitField(va, 2, 26, 0));
}
// 30 29 23 5
@@ -57,14 +59,18 @@ inline uint64_t encodeBranch26(SymbolDiagnostic d, uint64_t base, uint64_t va) {
// | |ilo| | immhi | |
// +-+---+---------+-------------------------------------+---------+
-inline uint64_t encodePage21(const Reloc &r, uint64_t base, uint64_t va) {
- checkInt(r, va, 35);
- return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5));
+inline void encodePage21(uint32_t *loc, const Reloc &r, uint32_t base,
+ uint64_t va) {
+ checkInt(loc, r, va, 35);
+ llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) |
+ bitField(va, 14, 19, 5));
}
-inline uint64_t encodePage21(SymbolDiagnostic d, uint64_t base, uint64_t va) {
- checkInt(d, va, 35);
- return (base | bitField(va, 12, 2, 29) | bitField(va, 14, 19, 5));
+inline void encodePage21(uint32_t *loc, SymbolDiagnostic d, uint32_t base,
+ uint64_t va) {
+ checkInt(loc, d, va, 35);
+ llvm::support::endian::write32le(loc, base | bitField(va, 12, 2, 29) |
+ bitField(va, 14, 19, 5));
}
// 21 10
@@ -72,7 +78,7 @@ inline uint64_t encodePage21(SymbolDiagnostic d, uint64_t base, uint64_t va) {
// | | imm12 | |
// +-------------------+-----------------------+-------------------+
-inline uint64_t encodePageOff12(uint32_t base, uint64_t va) {
+inline void encodePageOff12(uint32_t *loc, uint32_t base, uint64_t va) {
int scale = 0;
if ((base & 0x3b00'0000) == 0x3900'0000) { // load/store
scale = base >> 30;
@@ -82,7 +88,8 @@ inline uint64_t encodePageOff12(uint32_t base, uint64_t va) {
// TODO(gkm): extract embedded addend and warn if != 0
// uint64_t addend = ((base & 0x003FFC00) >> 10);
- return (base | bitField(va, scale, 12 - scale, 10));
+ llvm::support::endian::write32le(loc,
+ base | bitField(va, scale, 12 - scale, 10));
}
inline uint64_t pageBits(uint64_t address) {
@@ -99,9 +106,9 @@ inline void writeStub(uint8_t *buf8, const uint32_t stubCode[3],
pageBits(in.stubs->addr + sym.stubsIndex * stubCodeSize);
uint64_t lazyPointerVA =
in.lazyPointers->addr + sym.stubsIndex * LP::wordSize;
- buf32[0] = encodePage21({&sym, "stub"}, stubCode[0],
- pageBits(lazyPointerVA) - pcPageBits);
- buf32[1] = encodePageOff12(stubCode[1], lazyPointerVA);
+ encodePage21(&buf32[0], {&sym, "stub"}, stubCode[0],
+ pageBits(lazyPointerVA) - pcPageBits);
+ encodePageOff12(&buf32[1], stubCode[1], lazyPointerVA);
buf32[2] = stubCode[2];
}
@@ -114,27 +121,27 @@ inline void writeStubHelperHeader(uint8_t *buf8,
};
uint64_t loaderVA = in.imageLoaderCache->getVA();
SymbolDiagnostic d = {nullptr, "stub header helper"};
- buf32[0] = encodePage21(d, stubHelperHeaderCode[0],
- pageBits(loaderVA) - pcPageBits(0));
- buf32[1] = encodePageOff12(stubHelperHeaderCode[1], loaderVA);
+ encodePage21(&buf32[0], d, stubHelperHeaderCode[0],
+ pageBits(loaderVA) - pcPageBits(0));
+ encodePageOff12(&buf32[1], stubHelperHeaderCode[1], loaderVA);
buf32[2] = stubHelperHeaderCode[2];
uint64_t binderVA =
in.got->addr + in.stubHelper->stubBinder->gotIndex * LP::wordSize;
- buf32[3] = encodePage21(d, stubHelperHeaderCode[3],
- pageBits(binderVA) - pcPageBits(3));
- buf32[4] = encodePageOff12(stubHelperHeaderCode[4], binderVA);
+ encodePage21(&buf32[3], d, stubHelperHeaderCode[3],
+ pageBits(binderVA) - pcPageBits(3));
+ encodePageOff12(&buf32[4], stubHelperHeaderCode[4], binderVA);
buf32[5] = stubHelperHeaderCode[5];
}
inline void writeStubHelperEntry(uint8_t *buf8,
const uint32_t stubHelperEntryCode[3],
- const DylibSymbol &sym, uint64_t entryVA) {
+ const Symbol &sym, uint64_t entryVA) {
auto *buf32 = reinterpret_cast<uint32_t *>(buf8);
auto pcVA = [entryVA](int i) { return entryVA + i * sizeof(uint32_t); };
uint64_t stubHelperHeaderVA = in.stubHelper->addr;
buf32[0] = stubHelperEntryCode[0];
- buf32[1] = encodeBranch26({&sym, "stub helper"}, stubHelperEntryCode[1],
- stubHelperHeaderVA - pcVA(1));
+ encodeBranch26(&buf32[1], {&sym, "stub helper"}, stubHelperEntryCode[1],
+ stubHelperHeaderVA - pcVA(1));
buf32[2] = sym.lazyBindOffset;
}
diff --git a/lld/MachO/Arch/ARM64_32.cpp b/lld/MachO/Arch/ARM64_32.cpp
index f7b1439b8930..5be411e40342 100644
--- a/lld/MachO/Arch/ARM64_32.cpp
+++ b/lld/MachO/Arch/ARM64_32.cpp
@@ -31,7 +31,7 @@ struct ARM64_32 : ARM64Common {
ARM64_32();
void writeStub(uint8_t *buf, const Symbol &) const override;
void writeStubHelperHeader(uint8_t *buf) const override;
- void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
+ void writeStubHelperEntry(uint8_t *buf, const Symbol &,
uint64_t entryAddr) const override;
const RelocAttrs &getRelocAttrs(uint8_t type) const override;
};
@@ -96,7 +96,7 @@ static constexpr uint32_t stubHelperEntryCode[] = {
0x00000000, // 08: l0: .long 0
};
-void ARM64_32::writeStubHelperEntry(uint8_t *buf8, const DylibSymbol &sym,
+void ARM64_32::writeStubHelperEntry(uint8_t *buf8, const Symbol &sym,
uint64_t entryVA) const {
::writeStubHelperEntry(buf8, stubHelperEntryCode, sym, entryVA);
}
@@ -105,6 +105,10 @@ ARM64_32::ARM64_32() : ARM64Common(ILP32()) {
cpuType = CPU_TYPE_ARM64_32;
cpuSubtype = CPU_SUBTYPE_ARM64_V8;
+ modeDwarfEncoding = 0x04000000; // UNWIND_ARM_MODE_DWARF
+ subtractorRelocType = GENERIC_RELOC_INVALID; // FIXME
+ unsignedRelocType = GENERIC_RELOC_INVALID; // FIXME
+
stubSize = sizeof(stubCode);
stubHelperHeaderSize = sizeof(stubHelperHeaderCode);
stubHelperEntrySize = sizeof(stubHelperEntryCode);
diff --git a/lld/MachO/Arch/X86_64.cpp b/lld/MachO/Arch/X86_64.cpp
index 7e2155801fc2..d675356b9ffb 100644
--- a/lld/MachO/Arch/X86_64.cpp
+++ b/lld/MachO/Arch/X86_64.cpp
@@ -12,6 +12,7 @@
#include "Target.h"
#include "lld/Common/ErrorHandler.h"
+#include "mach-o/compact_unwind_encoding.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/Endian.h"
@@ -32,7 +33,7 @@ struct X86_64 : TargetInfo {
void writeStub(uint8_t *buf, const Symbol &) const override;
void writeStubHelperHeader(uint8_t *buf) const override;
- void writeStubHelperEntry(uint8_t *buf, const DylibSymbol &,
+ void writeStubHelperEntry(uint8_t *buf, const Symbol &,
uint64_t entryAddr) const override;
void relaxGotLoad(uint8_t *loc, uint8_t type) const override;
@@ -102,9 +103,9 @@ void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
switch (r.length) {
case 2:
if (r.type == X86_64_RELOC_UNSIGNED)
- checkUInt(r, value, 32);
+ checkUInt(loc, r, value, 32);
else
- checkInt(r, value, 32);
+ checkInt(loc, r, value, 32);
write32le(loc, value);
break;
case 3:
@@ -127,7 +128,7 @@ void X86_64::relocateOne(uint8_t *loc, const Reloc &r, uint64_t value,
static void writeRipRelative(SymbolDiagnostic d, uint8_t *buf, uint64_t bufAddr,
uint64_t bufOff, uint64_t destAddr) {
uint64_t rip = bufAddr + bufOff;
- checkInt(d, destAddr - rip, 32);
+ checkInt(buf, d, destAddr - rip, 32);
// For the instructions we care about, the RIP-relative address is always
// stored in the last 4 bytes of the instruction.
write32le(buf + bufOff - 4, destAddr - rip);
@@ -166,7 +167,7 @@ static constexpr uint8_t stubHelperEntry[] = {
0xe9, 0, 0, 0, 0, // 0x5: jmp <__stub_helper>
};
-void X86_64::writeStubHelperEntry(uint8_t *buf, const DylibSymbol &sym,
+void X86_64::writeStubHelperEntry(uint8_t *buf, const Symbol &sym,
uint64_t entryAddr) const {
memcpy(buf, stubHelperEntry, sizeof(stubHelperEntry));
write32le(buf + 1, sym.lazyBindOffset);
@@ -185,6 +186,10 @@ X86_64::X86_64() : TargetInfo(LP64()) {
cpuType = CPU_TYPE_X86_64;
cpuSubtype = CPU_SUBTYPE_X86_64_ALL;
+ modeDwarfEncoding = UNWIND_X86_MODE_DWARF;
+ subtractorRelocType = X86_64_RELOC_SUBTRACTOR;
+ unsignedRelocType = X86_64_RELOC_UNSIGNED;
+
stubSize = sizeof(stub);
stubHelperHeaderSize = sizeof(stubHelperHeader);
stubHelperEntrySize = sizeof(stubHelperEntry);