fix(relinker): load needed providers for unscoped Windows imports

This commit is contained in:
MathiasDevelopes 2026-10-11 10:59:39 +02:00 committed by Adrià Franch
parent 92ceadff7f
commit 2faa5dd6ed
2 changed files with 31 additions and 2 deletions

View File

@ -130,6 +130,7 @@ WindowsEntryStub WindowsEntryStubBuilder::Build(const std::uint32_t dataRva, con
std::vector<std::uint32_t> searchCounts;
std::vector<bool> platformTlsResolvers;
std::vector<bool> 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<std::uint32_t> 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<std::size_t> 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<std::size_t> 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);

View File

@ -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'),