From 341dafb7cadb6dfc18a716f0546a5504a93f57c1 Mon Sep 17 00:00:00 2001 From: ArjenS-LA Date: Mon, 12 Oct 2026 00:00:52 -0700 Subject: [PATCH] fix(relinker): rebase each origin in guest runpath lists --- .../relinker/src/guest/GuestModuleBuilder.cpp | 11 +++++++---- core/relinker/relinker/tests/test_guest_runpath.py | 10 +++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp b/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp index f6c8f8a49..f3d2d5336 100644 --- a/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp +++ b/core/relinker/relinker/src/guest/GuestModuleBuilder.cpp @@ -331,7 +331,7 @@ std::vector GuestModuleBuilder::Build(const std::filesystem::path }; for (const auto index : order) if (!windows && !deferred(index)) addNeeded("$ORIGIN/" + appDirectory(images[index]) + "/" + images[index].OutputName); for (const auto& name : hostLibraries) addNeeded(name); - if (!windows && runPath != "$ORIGIN" && !runPath.starts_with("$ORIGIN/") && !std::filesystem::path(runPath).is_absolute()) throw Domain::RelinkerException("Guest Linux run path must be absolute or begin with $ORIGIN"); + if (!windows && runPath != "$ORIGIN" && !runPath.starts_with("$ORIGIN/") && !runPath.starts_with("$ORIGIN:") && !std::filesystem::path(runPath).is_absolute()) throw Domain::RelinkerException("Guest Linux run path must be absolute or begin with $ORIGIN"); const auto outputDirectory = std::filesystem::absolute(outputPath).parent_path().lexically_normal(); std::vector artifacts; for (const auto index : order) { @@ -370,9 +370,12 @@ std::vector GuestModuleBuilder::Build(const std::filesystem::path if (windows) output = Elfpatcher::GuestModuleWriter().WriteWindows(image, runtime); else { std::string guestRunPath = runPath; - if (runPath == "$ORIGIN" || runPath.starts_with("$ORIGIN/")) { - const auto relativeRoot = outputDirectory.lexically_relative(destination.lexically_normal()).generic_string(); - guestRunPath = "$ORIGIN/" + relativeRoot + runPath.substr(7); + const auto relativeRoot = outputDirectory.lexically_relative(destination.lexically_normal()).generic_string(); + for (std::size_t position = 0; (position = guestRunPath.find("$ORIGIN", position)) != std::string::npos;) { + position += 7; + if (position != guestRunPath.size() && guestRunPath[position] != '/' && guestRunPath[position] != ':') continue; + guestRunPath.insert(position, "/" + relativeRoot); + position += relativeRoot.size() + 1; } std::vector needed; for (const auto dependency : dependencies[index]) { diff --git a/core/relinker/relinker/tests/test_guest_runpath.py b/core/relinker/relinker/tests/test_guest_runpath.py index 421199eda..754fee90a 100644 --- a/core/relinker/relinker/tests/test_guest_runpath.py +++ b/core/relinker/relinker/tests/test_guest_runpath.py @@ -17,7 +17,9 @@ def main(): checked = 0 for index, module_directory in enumerate(("sce_module", "prx")): for label, run_path in (("default", None), ("origin", "$ORIGIN"), - ("custom", "$ORIGIN/host libs"), ("absolute", str(work / "absolute libs"))): + ("custom", "$ORIGIN/host libs"), ("absolute", str(work / "absolute libs")), + ("list", "$ORIGIN/first:$ORIGIN/second"), + ("list-bare", "$ORIGIN:$ORIGIN/libs:$ORIGIN")): case = work / f"{index}-{label}" source = case / "input" / "input.elf" source.parent.mkdir(parents=True) @@ -41,8 +43,10 @@ def main(): assert 0 <= offset < len(strings) and end >= 0, (tags, strings) actual = strings[offset:end].decode() configured = run_path if run_path is not None else "$ORIGIN/libs" - expected = Path(configured.replace("$ORIGIN", str(output.parent))).resolve() - resolved = Path(actual.replace("$ORIGIN", str(artifact.parent))).resolve() + configured_paths = configured.split(":") if label.startswith("list") else [configured] + actual_paths = actual.split(":") if label.startswith("list") else [actual] + expected = [Path(path.replace("$ORIGIN", str(output.parent))).resolve() for path in configured_paths] + resolved = [Path(path.replace("$ORIGIN", str(artifact.parent))).resolve() for path in actual_paths] if resolved != expected or (label == "absolute" and actual != run_path): failures.append((str(relative), label, actual, str(resolved), str(expected))) checked += 1