From 2faa5dd6ed9fa23d2be4ffbbc4b58eb435262e9a Mon Sep 17 00:00:00 2001 From: MathiasDevelopes <25400788+MathiasDevelopes@users.noreply.github.com> Date: Sun, 11 Oct 2026 10:59:39 +0200 Subject: [PATCH] fix(relinker): load needed providers for unscoped Windows imports --- .../src/windows/WindowsEntryStubBuilder.cpp | 17 +++++++++++++++-- .../tests/test_windows_import_modules.py | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp b/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp index aa9b54d6f..83281042f 100644 --- a/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp +++ b/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp @@ -130,6 +130,7 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con std::vector searchCounts; std::vector platformTlsResolvers; std::vector imported(libraries.size()); + const bool unscopedImports = std::any_of(imports.begin(), imports.end(), [](const auto& import) { return import.Library.empty(); }); for (const auto& import : imports) { std::vector order; for (std::size_t index = 0; index < libraries.size(); ++index) { @@ -359,7 +360,7 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con } for (std::size_t index = 0; index < libraries.size(); ++index) { - if (index >= guestModules.size() && !imported[index]) continue; + if (index >= guestModules.size() && !imported[index] && !unscopedImports) continue; if (absolutePath && index >= guestModules.size()) { code.Rip({0x48, 0x8d, 0x0d}, libraryPaths[index]); } else { @@ -391,6 +392,12 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con code.Emit({0x48, 0x85, 0xc0}); const auto loadSucceeded = code.Branch({0x0f, 0x85}); captureLastError(); + std::optional unusedMissing; + if (index >= guestModules.size() && !imported[index]) { + code.Rip({0x8b, 0x05}, lastError); + code.Emit({0x83, 0xf8, 0x7e}); + unusedMissing = code.Branch({0x0f, 0x84}); + } if (dependencyDiagnostics) { writeString(loadFailed, true); } @@ -410,6 +417,12 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con if (dependencyDiagnostics) { writeString(loaded); } + if (unusedMissing) { + const auto next = code.Branch({0xe9}); + code.PatchBranch(*unusedMissing, code.GetRva()); + if (dependencyDiagnostics) writeString(skippedModule, true); + code.PatchBranch(next, code.GetRva()); + } } std::vector unresolvedBranches; @@ -526,7 +539,7 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con code.PatchBranch(branch, code.GetRva()); writeString(searched, true); for (std::size_t index = 0; index < resolvedPaths.size(); ++index) { - if (index >= guestModules.size() && !imported[index]) continue; + if (index >= guestModules.size() && !imported[index] && !unscopedImports) continue; writeString(indent, true); writeString(resolvedPaths[index], true); writeString(newline, true); diff --git a/core/relinker/relinker/tests/test_windows_import_modules.py b/core/relinker/relinker/tests/test_windows_import_modules.py index 110ef7b39..5c361331a 100644 --- a/core/relinker/relinker/tests/test_windows_import_modules.py +++ b/core/relinker/relinker/tests/test_windows_import_modules.py @@ -230,6 +230,22 @@ def main(): assert result.returncode == 0, (result.stdout, result.stderr) assert output.is_file() and (output.parent / 'app0' / 'prx' / 'a.prx.guest.prx').is_file() + result, native_output = convert('unscoped-native-provider', 'b.prx') + assert result.returncode == 0, result.stderr + case = work / 'unscoped-native-import' + (case / 'prx').mkdir(parents=True) + (case / 'libs').mkdir() + native_provider = native_output.parent / 'app0' / 'prx' / 'b.prx.guest.prx' + (case / 'libs' / 'available.prx').write_bytes(native_provider.read_bytes()) + source = case / 'input.elf' + source.write_bytes(executable('available.prx', 'shared', extra_dependencies=('unused.prx',))) + output = case / 'output.exe' + result = subprocess.run([str(relinker), '--windows', str(source), str(output)], capture_output=True, text=True, timeout=30) + assert result.returncode == 0, result.stderr + if os.name == 'nt': + run = subprocess.run([str(output)], capture_output=True, text=True, timeout=30) + assert run.returncode == 22 and 'unused.prx' not in run.stderr, (run.returncode, run.stdout, run.stderr) + check_internal_guest_libc(convert, work, relinker) for filename, module_name in [('foo.native.prx', 'foo_native'),