From 3c8b18bc512ad87b379b4b7c06d52ca2d13860b2 Mon Sep 17 00:00:00 2001 From: Daniel Bertalan Date: Wed, 10 Jul 2024 18:40:23 +0200 Subject: [PATCH] [lld-macho] Use larger ordinal encoding if import count requires it (#98305) The default `dyld_chained_import` entry format only allocates 8 bits to the library ordinal, of which values 0xF1 - 0xFF are reserved for special ordinals (`BIND_SPECIAL_DYLIB_*` values). If there are more than 240 imported dylibs (as in the case of component builds of Chromium), we need to switch to `dyld_chained_import_addend64`, which stores 16-bit ordinals. --- lld/MachO/SyntheticSections.cpp | 34 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lld/MachO/SyntheticSections.cpp b/lld/MachO/SyntheticSections.cpp index 6a7284fefcf29d..3d77835d117efe 100644 --- a/lld/MachO/SyntheticSections.cpp +++ b/lld/MachO/SyntheticSections.cpp @@ -544,6 +544,14 @@ static void flushOpcodes(const BindIR &op, raw_svector_ostream &os) { } } +static bool needsWeakBind(const Symbol &sym) { + if (auto *dysym = dyn_cast(&sym)) + return dysym->isWeakDef(); + if (auto *defined = dyn_cast(&sym)) + return defined->isExternalWeakDef(); + return false; +} + // 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()) @@ -553,6 +561,8 @@ static int16_t ordinalForDylibSymbol(const DylibSymbol &dysym) { } static int16_t ordinalForSymbol(const Symbol &sym) { + if (config->emitChainedFixups && needsWeakBind(sym)) + return BIND_SPECIAL_DYLIB_WEAK_LOOKUP; if (const auto *dysym = dyn_cast(&sym)) return ordinalForDylibSymbol(*dysym); assert(cast(&sym)->interposable); @@ -2276,14 +2286,6 @@ bool ChainedFixupsSection::isNeeded() const { return true; } -static bool needsWeakBind(const Symbol &sym) { - if (auto *dysym = dyn_cast(&sym)) - return dysym->isWeakDef(); - if (auto *defined = dyn_cast(&sym)) - return defined->isExternalWeakDef(); - return false; -} - void ChainedFixupsSection::addBinding(const Symbol *sym, const InputSection *isec, uint64_t offset, int64_t addend) { @@ -2312,7 +2314,7 @@ ChainedFixupsSection::getBinding(const Symbol *sym, int64_t addend) const { return {it->second, 0}; } -static size_t writeImport(uint8_t *buf, int format, uint32_t libOrdinal, +static size_t writeImport(uint8_t *buf, int format, int16_t libOrdinal, bool weakRef, uint32_t nameOffset, int64_t addend) { switch (format) { case DYLD_CHAINED_IMPORT: { @@ -2430,11 +2432,8 @@ void ChainedFixupsSection::writeTo(uint8_t *buf) const { uint64_t nameOffset = 0; for (auto [import, idx] : bindings) { const Symbol &sym = *import.first; - int16_t libOrdinal = needsWeakBind(sym) - ? (int64_t)BIND_SPECIAL_DYLIB_WEAK_LOOKUP - : ordinalForSymbol(sym); - buf += writeImport(buf, importFormat, libOrdinal, sym.isWeakRef(), - nameOffset, import.second); + buf += writeImport(buf, importFormat, ordinalForSymbol(sym), + sym.isWeakRef(), nameOffset, import.second); nameOffset += sym.getName().size() + 1; } @@ -2459,7 +2458,12 @@ void ChainedFixupsSection::finalizeContents() { error("cannot encode chained fixups: imported symbols table size " + Twine(symtabSize) + " exceeds 4 GiB"); - if (needsLargeAddend || !isUInt<23>(symtabSize)) + bool needsLargeOrdinal = any_of(bindings, [](const auto &p) { + // 0xF1 - 0xFF are reserved for special ordinals in the 8-bit encoding. + return ordinalForSymbol(*p.first.first) > 0xF0; + }); + + if (needsLargeAddend || !isUInt<23>(symtabSize) || needsLargeOrdinal) importFormat = DYLD_CHAINED_IMPORT_ADDEND64; else if (needsAddend) importFormat = DYLD_CHAINED_IMPORT_ADDEND;