diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /lld/MachO/Arch | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Diffstat (limited to 'lld/MachO/Arch')
| -rw-r--r-- | lld/MachO/Arch/ARM.cpp | 4 | ||||
| -rw-r--r-- | lld/MachO/Arch/ARM64.cpp | 322 | ||||
| -rw-r--r-- | lld/MachO/Arch/ARM64Common.cpp | 41 | ||||
| -rw-r--r-- | lld/MachO/Arch/ARM64Common.h | 59 | ||||
| -rw-r--r-- | lld/MachO/Arch/ARM64_32.cpp | 8 | ||||
| -rw-r--r-- | lld/MachO/Arch/X86_64.cpp | 15 |
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); |
