diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -277,6 +277,10 @@ uint64_t offset = 0; int64_t addend = 0; }; +struct BindIR { + uint8_t opcode = 0xF0; + uint64_t data = 0; +}; } // namespace // Encode a sequence of opcodes that tell dyld to write the address of symbol + @@ -287,32 +291,50 @@ // lastBinding. static void encodeBinding(const OutputSection *osec, uint64_t outSecOff, int64_t addend, Binding &lastBinding, - raw_svector_ostream &os) { + std::vector &opcodes) { OutputSegment *seg = osec->parent; uint64_t offset = osec->getSegmentOffset() + outSecOff; if (lastBinding.segment != seg) { - os << static_cast(BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | - seg->index); - encodeULEB128(offset, os); + opcodes.push_back( + {BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB | seg->index, offset}); lastBinding.segment = seg; lastBinding.offset = offset; } else if (lastBinding.offset != offset) { - os << static_cast(BIND_OPCODE_ADD_ADDR_ULEB); - encodeULEB128(offset - lastBinding.offset, os); + opcodes.push_back({BIND_OPCODE_ADD_ADDR_ULEB, offset - lastBinding.offset}); lastBinding.offset = offset; } if (lastBinding.addend != addend) { - os << static_cast(BIND_OPCODE_SET_ADDEND_SLEB); - encodeSLEB128(addend, os); + opcodes.push_back( + {BIND_OPCODE_SET_ADDEND_SLEB, static_cast(addend)}); lastBinding.addend = addend; } - os << static_cast(BIND_OPCODE_DO_BIND); + opcodes.push_back({BIND_OPCODE_DO_BIND, 0}); // DO_BIND causes dyld to both perform the binding and increment the offset lastBinding.offset += target->wordSize; } +static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) { + uint8_t opcode = op.opcode & BIND_OPCODE_MASK; + switch (opcode) { + case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: + case BIND_OPCODE_ADD_ADDR_ULEB: + os << op.opcode; + encodeULEB128(op.data, os); + break; + case BIND_OPCODE_SET_ADDEND_SLEB: + os << op.opcode; + encodeSLEB128(static_cast(op.data), os); + break; + case BIND_OPCODE_DO_BIND: + os << op.opcode; + break; + default: + llvm_unreachable("cannot bind to an unrecognized symbol"); + } +} + // Non-weak bindings need to have their dylib ordinal encoded as well. static int16_t ordinalForDylibSymbol(const DylibSymbol &dysym) { if (config->namespaceKind == NamespaceKind::flat || dysym.isDynamicLookup()) @@ -392,9 +414,6 @@ for (auto &p : sortBindings(bindingsMap)) { const DylibSymbol *sym = p.first; std::vector &bindings = p.second; - llvm::sort(bindings, [](const BindingEntry &a, const BindingEntry &b) { - return a.target.getVA() < b.target.getVA(); - }); uint8_t flags = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM; if (sym->isWeakRef()) flags |= BIND_SYMBOL_FLAGS_WEAK_IMPORT; @@ -405,10 +424,13 @@ encodeDylibOrdinal(ordinal, os); lastOrdinal = ordinal; } + std::vector opcodes; for (const BindingEntry &b : bindings) encodeBinding(b.target.isec->parent, b.target.isec->getOffset(b.target.offset), b.addend, - lastBinding, os); + lastBinding, opcodes); + for (const auto &op : opcodes) + flushOpcodes(op, os); } if (!bindingsMap.empty()) os << static_cast(BIND_OPCODE_DONE); @@ -434,10 +456,13 @@ os << static_cast(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM) << sym->getName() << '\0' << static_cast(BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER); + std::vector opcodes; for (const BindingEntry &b : bindings) encodeBinding(b.target.isec->parent, b.target.isec->getOffset(b.target.offset), b.addend, - lastBinding, os); + lastBinding, opcodes); + for (const auto &op : opcodes) + flushOpcodes(op, os); } if (!bindingsMap.empty() || !definitions.empty()) os << static_cast(BIND_OPCODE_DONE);