feat: resolve delay-loaded system libraries to the runtime's components

Assisted-by: Claude Code:claude-opus-5-5
AI-Scope: Made the loader follow delay imports when choosing components, with a delay-load test.
This commit is contained in:
mirkobrombin committed 2026-10-27 10:32:01 +00:00
1 parent fdad9c4bd4
commit cea6ca7a7a
4 files changed
+44 -2

No files matched your search

+14
View File
@@ -3537,6 +3537,20 @@ if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|amd64|AMD64)$")
${DELAY_FIXTURES}/client.obj ${DELAY_FIXTURES}/helper.obj ${DELAY_FIXTURES}/delayed.lib ${RAVEN_KERNEL32_IMPORT}
DEPENDS ${DELAY_FIXTURES}/client.obj ${DELAY_FIXTURES}/helper.obj ${DELAY_FIXTURES}/delayed.lib VERBATIM)
add_custom_target(delay_pe_fixtures ALL DEPENDS ${DELAY_FIXTURES}/client.exe ${DELAY_FIXTURES}/delayed.dll)
# A program that delay-loads the setup API gets the component behind it as one that imports it does; its name must not look like an
# installer's, which gets the component anyway.
# lld-link delay-loads only through an import library of its own format, written here for the one function the client calls.
add_custom_command(OUTPUT ${DELAY_FIXTURES}/cabinet-client.exe
COMMAND ${RAVEN_MINGW64} -O1 -fno-builtin -fno-stack-protector -c ${LOADER_SOURCES}/delay_setupapi_client.c
-o ${DELAY_FIXTURES}/cabinet-client.obj
COMMAND ${RAVEN_LLD_LINK} /lib /machine:x64 /def:${LOADER_SOURCES}/delay_setupapi.def /out:${DELAY_FIXTURES}/setupapi.lib
COMMAND ${RAVEN_LLD_LINK} /entry:raven_entry /subsystem:console /nodefaultlib /base:0x192000000
/delayload:setupapi.dll /out:${DELAY_FIXTURES}/cabinet-client.exe
${DELAY_FIXTURES}/cabinet-client.obj ${DELAY_FIXTURES}/helper.obj ${DELAY_FIXTURES}/setupapi.lib ${RAVEN_KERNEL32_IMPORT}
DEPENDS ${LOADER_SOURCES}/delay_setupapi_client.c ${LOADER_SOURCES}/delay_setupapi.def ${DELAY_FIXTURES}/helper.obj VERBATIM)
add_custom_target(delay_setupapi_fixture ALL DEPENDS ${DELAY_FIXTURES}/cabinet-client.exe)
add_test(NAME native_delay_setupapi COMMAND raven --run-process --execution=native ${DELAY_FIXTURES}/cabinet-client.exe)
set_tests_properties(native_delay_setupapi PROPERTIES TIMEOUT 30 PASS_REGULAR_EXPRESSION "Native entry returned 0 ")
add_executable(delay_loader_test nt/delay_loader_test.cpp)
target_link_libraries(delay_loader_test PRIVATE raven_cpu)
add_dependencies(delay_loader_test delay_pe_fixtures raven-bootstrap)
+5 -2
View File
@@ -492,7 +492,7 @@ int main(int argc, char **argv)
if (std::filesystem::exists(component))
modules.add("raven-rtl.dll", read_file(component.c_str()));
}
// The libraries the program and the DLLs shipped beside it import, by lowercase file name.
// The libraries the program and the DLLs shipped beside it import, at once or lazily, by lowercase file name.
const auto imported_libraries = [&] {
std::set<std::string> names;
std::vector<std::string> pending;
@@ -509,8 +509,11 @@ int main(int argc, char **argv)
if (names.insert(lower(symbol.module)).second)
pending.push_back(lower(symbol.module));
};
for (const auto &item : modules.all())
for (const auto &item : modules.all()) {
visit(item.second->imports);
for (const auto &descriptor : item.second->image.delay_imports())
visit(descriptor.imports);
}
while (!pending.empty()) {
const auto name = pending.back();
pending.pop_back();
+3
View File
@@ -0,0 +1,3 @@
LIBRARY setupapi.dll
EXPORTS
SetupIterateCabinetW
+22
View File
@@ -0,0 +1,22 @@
#include <windows.h>
#include <setupapi.h>
#include <delayimp.h>
PfnDliHook __pfnDliNotifyHook2 = NULL;
PfnDliHook __pfnDliFailureHook2 = NULL;
static UINT CALLBACK visit(PVOID context, UINT notification, UINT_PTR first, UINT_PTR second)
{
++*(int *)context;
return NO_ERROR;
}
/* A program that loads the setup API only lazily, as large installers delay-load it, still extracts cabinets through it: a cabinet that
* does not exist is refused without visiting any file. */
int raven_entry(void)
{
int visited = 0;
if (SetupIterateCabinetW(L"C:\\raven-missing.cab", 0, visit, &visited)) return 1;
if (visited) return 2;
return 0;
}