[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.
This commit is contained in:
parent
e3fe8eee3c
commit
3c8b18bc51
@ -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<DylibSymbol>(&sym))
|
||||
return dysym->isWeakDef();
|
||||
if (auto *defined = dyn_cast<Defined>(&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<DylibSymbol>(&sym))
|
||||
return ordinalForDylibSymbol(*dysym);
|
||||
assert(cast<Defined>(&sym)->interposable);
|
||||
@ -2276,14 +2286,6 @@ bool ChainedFixupsSection::isNeeded() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool needsWeakBind(const Symbol &sym) {
|
||||
if (auto *dysym = dyn_cast<DylibSymbol>(&sym))
|
||||
return dysym->isWeakDef();
|
||||
if (auto *defined = dyn_cast<Defined>(&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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user