Skip to content

Commit 2b1fc96

Browse files
committed
[MachO] Ensure that weak bound symbols are not resolved to their import address
Fixes #7989. Also corrects an oversight from d92b368 in handling of library ordinals >= 128.
1 parent d92b368 commit 2b1fc96

2 files changed

Lines changed: 57 additions & 79 deletions

File tree

view/macho/chained_fixups.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ ImportEntry ReadChainedImport32(BinaryReader& reader, std::span<const char> symb
247247
return {
248248
std::string_view(&symbolData[import.name_offset]),
249249
0,
250-
static_cast<int8_t>(import.lib_ordinal),
250+
import.lib_ordinal > 0xF0 ? static_cast<int8_t>(import.lib_ordinal) : static_cast<int32_t>(import.lib_ordinal),
251251
(bool)import.weak_import,
252252
};
253253
}
@@ -259,7 +259,7 @@ ImportEntry ReadChainedImportAddend32(BinaryReader& reader, std::span<const char
259259
return {
260260
std::string_view(&symbolData[import.name_offset]),
261261
static_cast<uint32_t>(import.addend),
262-
static_cast<int8_t>(import.lib_ordinal),
262+
import.lib_ordinal > 0xF0 ? static_cast<int8_t>(import.lib_ordinal) : static_cast<int32_t>(import.lib_ordinal),
263263
(bool)import.weak_import,
264264
};
265265
}
@@ -271,7 +271,7 @@ ImportEntry ReadChainedImportAddend64(BinaryReader& reader, std::span<const char
271271
return {
272272
std::string_view(&symbolData[import.name_offset]),
273273
import.addend,
274-
static_cast<int16_t>(import.lib_ordinal),
274+
import.lib_ordinal > 0xFFF0 ? static_cast<int16_t>(import.lib_ordinal) : static_cast<int32_t>(import.lib_ordinal),
275275
(bool)import.weak_import,
276276
};
277277
}

view/macho/machoview.cpp

Lines changed: 54 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,6 +1710,51 @@ bool MachoView::Init()
17101710
}
17111711

17121712

1713+
static Ref<Symbol> FindInternalSymbol(BinaryView* view, const std::string& name)
1714+
{
1715+
// When multiple symbols are defined with the same name, which can happen when a symbol is both
1716+
// in the symbol table and self-bound, `GetSymbolByRawName` prefers the symbol with the lowest
1717+
// type value. Since `ImportAddressSymbol` is a lower value than `DataSymbol`/`FunctionSymbol`,
1718+
// it would return the import stub rather than the actual symbol definition. Filter it out.
1719+
auto symbols = view->GetSymbolsByRawName(name, view->GetInternalNameSpace());
1720+
auto it = std::ranges::find_if(symbols, [](const Ref<Symbol>& sym) {
1721+
return sym->GetType() != ImportAddressSymbol;
1722+
});
1723+
return it != symbols.end() ? *it : nullptr;
1724+
}
1725+
1726+
1727+
static Ref<Symbol> ResolveBindSymbol(BinaryView* view, const MachOHeader& header, const std::string& name, int32_t ordinal)
1728+
{
1729+
switch (ordinal)
1730+
{
1731+
case BindSpecialDylibSelf:
1732+
return FindInternalSymbol(view, name);
1733+
1734+
case BindSpecialDylibMainExecutable:
1735+
case BindSpecialDylibFlatLookup:
1736+
case BindSpecialDylibWeakLookup:
1737+
{
1738+
Ref<Symbol> symbol;
1739+
1740+
// Prefer internal symbols for executables, and external symbols for everything else.
1741+
if (header.ident.filetype == MH_EXECUTE)
1742+
symbol = FindInternalSymbol(view, name);
1743+
if (!symbol)
1744+
symbol = view->GetSymbolByRawName(name, view->GetExternalNameSpace());
1745+
if (!symbol && header.ident.filetype != MH_EXECUTE)
1746+
symbol = FindInternalSymbol(view, name);
1747+
return symbol;
1748+
}
1749+
1750+
default:
1751+
if (ordinal > 0)
1752+
return view->GetSymbolByRawName(name, view->GetExternalNameSpace());
1753+
return nullptr;
1754+
}
1755+
}
1756+
1757+
17131758
bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_t preferredImageBase,
17141759
std::string preferredImageBaseDesc, bool platformSetByUser)
17151760
{
@@ -2272,86 +2317,19 @@ bool MachoView::InitializeHeader(MachOHeader& header, bool isMainHeader, uint64_
22722317
Ref<Metadata> symbolToLibraryMapping = new Metadata(KeyValueDataType);
22732318
for (auto& [relocation, name, ordinal] : header.bindingRelocations)
22742319
{
2275-
bool handled = false;
2276-
2277-
switch (ordinal)
2320+
if (auto symbol = ResolveBindSymbol(this, header, name, ordinal); symbol)
22782321
{
2279-
case BindSpecialDylibSelf:
2280-
{
2281-
// When multiple symbols are defined with the same name, which can happen for a symbol is both in the
2282-
// symbol table and self-bound, `GetSymbolByRawName` prefers the symbol with the lowest type value.
2283-
// Since `ImportAddressSymbol` is a lower value than `DataSymbol`, using `GetSymbolByRawName` would
2284-
// return the symbol representing the import we're binding to rather than the actual symbol definition.
2285-
auto symbols = GetSymbolsByRawName(name, GetInternalNameSpace());
2286-
auto it = std::ranges::find_if(symbols, [](const Ref<Symbol>& sym) {
2287-
return sym->GetType() != ImportAddressSymbol;
2288-
});
2289-
2290-
if (it != symbols.end())
2291-
{
2292-
auto symbol = *it;
2293-
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2294-
if (objcProcessor)
2295-
objcProcessor->AddRelocatedPointer(relocation.address, symbol->GetAddress());
2296-
handled = true;
2297-
}
2298-
break;
2322+
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2323+
if (objcProcessor && symbol->GetNameSpace() == GetInternalNameSpace())
2324+
objcProcessor->AddRelocatedPointer(relocation.address, symbol->GetAddress());
22992325
}
2300-
2301-
case BindSpecialDylibMainExecutable:
2302-
case BindSpecialDylibFlatLookup:
2303-
case BindSpecialDylibWeakLookup:
2304-
// In cases where we are the primary executable, flat lookup should find us first,
2305-
// it seems like our best course of action is to try and find internally first on
2306-
// executables, and externally on libraries.
2307-
if (header.ident.filetype == MH_EXECUTE)
2308-
{
2309-
if (auto symbol = GetSymbolByRawName(name, GetInternalNameSpace()); symbol)
2310-
{
2311-
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2312-
if (objcProcessor)
2313-
objcProcessor->AddRelocatedPointer(relocation.address, symbol->GetAddress());
2314-
handled = true;
2315-
}
2316-
else if (auto symbol = GetSymbolByRawName(name, GetExternalNameSpace()); symbol)
2317-
{
2318-
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2319-
handled = true;
2320-
}
2321-
}
2322-
else
2323-
{
2324-
if (auto symbol = GetSymbolByRawName(name, GetExternalNameSpace()); symbol)
2325-
{
2326-
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2327-
handled = true;
2328-
}
2329-
else if (auto symbol = GetSymbolByRawName(name, GetInternalNameSpace()); symbol)
2330-
{
2331-
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2332-
if (objcProcessor)
2333-
objcProcessor->AddRelocatedPointer(relocation.address, symbol->GetAddress());
2334-
handled = true;
2335-
}
2336-
}
2337-
break;
2338-
2339-
default:
2340-
if (ordinal > 0)
2341-
{
2342-
if (auto symbol = GetSymbolByRawName(name, GetExternalNameSpace()))
2343-
{
2344-
DefineRelocation(m_arch, relocation, symbol, relocation.address);
2345-
handled = true;
2346-
}
2347-
if (ordinal - 1 < header.dylibs.size())
2348-
symbolToLibraryMapping->SetValueForKey(name, new Metadata(header.dylibs[ordinal - 1].first));
2349-
}
2350-
break;
2326+
else
2327+
{
2328+
m_logger->LogErrorF("Failed to find symbol {:?} for bind at {:#x} (ordinal: {})", name, relocation.address, ordinal);
23512329
}
23522330

2353-
if (!handled)
2354-
m_logger->LogErrorF("Failed to find external symbol {:?}, couldn't bind symbol at {:#x}", name, relocation.address);
2331+
if (ordinal > 0 && ordinal - 1 < header.dylibs.size())
2332+
symbolToLibraryMapping->SetValueForKey(name, new Metadata(header.dylibs[ordinal - 1].first));
23552333
}
23562334

23572335
StoreMetadata("SymbolExternalLibraryMapping", std::move(symbolToLibraryMapping), true);

0 commit comments

Comments
 (0)