diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index f8fd8039fe66..4660de2490ce 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -484,6 +484,9 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_guest_symbol_names.py $) add_test(NAME guest_registry COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_guest_registry.py $) + add_test(NAME needed_libraries COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_needed_libraries.py $) + set_tests_properties(needed_libraries PROPERTIES TIMEOUT 30) add_test(NAME macos_output COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_macos_output.py $) add_test(NAME guest_host_libc COMMAND ${Python3_EXECUTABLE} diff --git a/core/relinker/domain/include/domain/Types.hpp b/core/relinker/domain/include/domain/Types.hpp index e488940a5fdc..f505333ec730 100644 --- a/core/relinker/domain/include/domain/Types.hpp +++ b/core/relinker/domain/include/domain/Types.hpp @@ -101,6 +101,7 @@ struct SysVDynamicSection { std::map ImportModules; std::set FunctionImports; std::set UnmatchedImportModules; + std::vector NeededLibraries; }; struct CallRegistryEntry { diff --git a/core/relinker/main.cpp b/core/relinker/main.cpp index 07f448aefce5..d7ad6f68f669 100644 --- a/core/relinker/main.cpp +++ b/core/relinker/main.cpp @@ -265,6 +265,7 @@ int Run(const int argc, char* argv[]) { checkOutputInputs(std::filesystem::absolute("windows-diagnostics-imports.txt"), "Windows import diagnostics"); std::vector registryPaths; + std::vector neededPaths; if (args.writeRegistry) { for (const auto& executable : executables) { const std::filesystem::path outFsPath = Io::NativePath(executable.OutputPath); @@ -274,6 +275,12 @@ int Run(const int argc, char* argv[]) { for (const auto& artifact : guestArtifacts) registryPaths.push_back(outFsPath.parent_path() / Io::NativePath(Io::Utf8Path(outFsPath.stem()) + "." + Io::Utf8Path(artifact.Path.filename()) + ".registry.json")); for (const auto& path : registryPaths) checkOutputInputs(path, "Registry"); + for (const auto& path : registryPaths) { + auto name = Io::Utf8Path(path.filename()); + name.resize(name.size() - std::string(".registry.json").size()); + neededPaths.push_back(path.parent_path() / Io::NativePath(name + ".needed.json")); + } + for (const auto& path : neededPaths) checkOutputInputs(path, "Needed libraries"); } checkOutputInputs(Io::NativePath(absPath), "Executable"); @@ -312,10 +319,14 @@ int Run(const int argc, char* argv[]) { } if (args.writeRegistry) { const auto registryWriter = std::make_shared(); - for (std::size_t index = 0; index < executables.size(); ++index) + for (std::size_t index = 0; index < executables.size(); ++index) { fileWriter.Write(Io::Utf8Path(registryPaths[index]), registryWriter->WriteCallRegistry(executables[index].Result.RegistryEntries)); - for (std::size_t index = 0; index < guestArtifacts.size(); ++index) + fileWriter.Write(Io::Utf8Path(neededPaths[index]), registryWriter->WriteNeededLibraries(executables[index].Result.DynamicSection.NeededLibraries)); + } + for (std::size_t index = 0; index < guestArtifacts.size(); ++index) { fileWriter.Write(Io::Utf8Path(registryPaths[executables.size() + index]), registryWriter->WriteModuleImports(guestArtifacts[index].Imports)); + fileWriter.Write(Io::Utf8Path(neededPaths[executables.size() + index]), registryWriter->WriteNeededLibraries(guestArtifacts[index].NeededLibraries)); + } } progress.Finish(); if (desktopEntry) std::cout << "Desktop entry: " << Io::Utf8Path(desktopEntryWriter.Write(*desktopEntry)) << '\n'; diff --git a/core/relinker/relinker/include/relinker/domain/ICallRegistryWriter.hpp b/core/relinker/relinker/include/relinker/domain/ICallRegistryWriter.hpp index d528667e9734..57f2e9c218dd 100644 --- a/core/relinker/relinker/include/relinker/domain/ICallRegistryWriter.hpp +++ b/core/relinker/relinker/include/relinker/domain/ICallRegistryWriter.hpp @@ -13,6 +13,7 @@ class ICallRegistryWriter { virtual std::string WriteCallRegistry(const std::vector& entries) = 0; virtual std::string WriteModuleImports(const std::vector& entries) = 0; + virtual std::string WriteNeededLibraries(const std::vector& libraries) = 0; }; } diff --git a/core/relinker/relinker/include/relinker/guest/GuestImage.hpp b/core/relinker/relinker/include/relinker/guest/GuestImage.hpp index bef96dbe10ed..31e5781a547f 100644 --- a/core/relinker/relinker/include/relinker/guest/GuestImage.hpp +++ b/core/relinker/relinker/include/relinker/guest/GuestImage.hpp @@ -66,6 +66,7 @@ struct GuestArtifact { std::vector Bytes; std::vector Imports; std::filesystem::path SourcePath; + std::vector NeededLibraries; }; struct GuestModuleInput { diff --git a/core/relinker/relinker/include/relinker/output/CallRegistryWriter.hpp b/core/relinker/relinker/include/relinker/output/CallRegistryWriter.hpp index 79b196f86932..5c16c9057b61 100644 --- a/core/relinker/relinker/include/relinker/output/CallRegistryWriter.hpp +++ b/core/relinker/relinker/include/relinker/output/CallRegistryWriter.hpp @@ -9,6 +9,7 @@ class CallRegistryWriter : public ICallRegistryWriter { public: std::string WriteCallRegistry(const std::vector& entries) override; std::string WriteModuleImports(const std::vector& entries) override; + std::string WriteNeededLibraries(const std::vector& libraries) override; }; } diff --git a/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp b/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp index d7598f0a26cd..b9844c22cf6a 100644 --- a/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp +++ b/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp @@ -277,6 +277,7 @@ std::vector GuestModuleBuilder::Build(const std::filesystem::path for (const auto& name : neededNames) addHost(name); for (const auto& image : images) for (const auto& dependency : image.Dependencies) addHost(dependency); if (uniqueHosts.contains("libSceLibcInternal.prx") && uniqueHosts.insert("libc.prx").second) hostLibraries.push_back("libc.prx"); + dynamic.NeededLibraries = hostLibraries; dynamic.DynamicSegmentData.clear(); const auto addNeeded = [&](const std::string& name) { Io::AppendU64(dynamic.DynamicSegmentData, 1); @@ -356,7 +357,10 @@ std::vector GuestModuleBuilder::Build(const std::filesystem::path } } dynamic.GuestModules.push_back(std::move(runtime)); - artifacts.push_back({target, std::move(output), std::move(imports), image.SourcePath}); + std::vector neededLibraries; + for (const auto& name : image.Dependencies) + if (findGuest(name) == guestNames.end()) neededLibraries.push_back(name); + artifacts.push_back({target, std::move(output), std::move(imports), image.SourcePath, std::move(neededLibraries)}); progress.Report({Domain::ProgressStage::Modules, Io::Utf8Path(image.SourcePath), artifacts.size(), order.size()}); } return artifacts; diff --git a/core/relinker/relinker/src/output/CallRegistryWriter.cpp b/core/relinker/relinker/src/output/CallRegistryWriter.cpp index 7c8c909e6306..8fbd461e8962 100644 --- a/core/relinker/relinker/src/output/CallRegistryWriter.cpp +++ b/core/relinker/relinker/src/output/CallRegistryWriter.cpp @@ -82,4 +82,16 @@ std::string CallRegistryWriter::WriteModuleImports(const std::vector& libraries) { + std::ostringstream out; + out << "[\n"; + for (std::size_t index = 0; index < libraries.size(); ++index) { + out << " " << _jsonString(libraries[index]); + if (index + 1 < libraries.size()) out << ","; + out << "\n"; + } + out << "]\n"; + return out.str(); +} + } diff --git a/core/relinker/relinker/src/output/SysVDynamicSectionBuilder.cpp b/core/relinker/relinker/src/output/SysVDynamicSectionBuilder.cpp index 32cb6523c4ee..0d8bdd763fef 100644 --- a/core/relinker/relinker/src/output/SysVDynamicSectionBuilder.cpp +++ b/core/relinker/relinker/src/output/SysVDynamicSectionBuilder.cpp @@ -68,6 +68,7 @@ SysVDynamicSection SysVDynamicSectionBuilder::BuildDynamicSection( std::uint32_t originalJmprelCount) { SysVDynamicSection result; + result.NeededLibraries = neededLibraries; result.DynStrData.push_back(0); std::vector neededOffsets; diff --git a/core/relinker/relinker/tests/test_call_registry.py b/core/relinker/relinker/tests/test_call_registry.py index a3d02c7d2802..1bc1749afeb5 100644 --- a/core/relinker/relinker/tests/test_call_registry.py +++ b/core/relinker/relinker/tests/test_call_registry.py @@ -38,6 +38,9 @@ def main(): "callSites": ["0x200"], "callSitesResolved": True, "weak": False}] if entries != expected: raise AssertionError((name, options, entries)) + needed = json.loads(output.with_suffix(".needed.json").read_text(encoding="utf-8")) + if needed != ["lib.so"]: + raise AssertionError((name, options, needed)) strings = b"\0lib.so\0" + names[0].encode("utf-8") + b"\0" image = fixture(str_size=len(strings), table_bytes=strings) struct.pack_into("