diff --git a/core/relinker/CMakeLists.txt b/core/relinker/CMakeLists.txt index d3bdf0051..bc5a3536d 100644 --- a/core/relinker/CMakeLists.txt +++ b/core/relinker/CMakeLists.txt @@ -381,6 +381,9 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_windows_gui.py $) add_test(NAME windows_working_directory COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_windows_working_directory.py $) + add_test(NAME windows_runpath COMMAND ${Python3_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_windows_runpath.py $) + set_tests_properties(windows_runpath PROPERTIES TIMEOUT 30) add_test(NAME windows_address_space COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_windows_address_space.py $) add_test(NAME windows_tls_thread_pointer COMMAND ${Python3_EXECUTABLE} diff --git a/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp b/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp index 83281042f..a5ea5b7e3 100644 --- a/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp +++ b/core/relinker/elfpatcher/src/windows/WindowsEntryStubBuilder.cpp @@ -26,6 +26,8 @@ std::string normalizeRunPath(std::string path) { path = "."; if (path.starts_with("$ORIGIN\\")) path.erase(0, 8); + if (path.empty()) + path = "."; if (path.find('$') != std::string::npos) throw Domain::RelinkerException("Unsupported variable in Windows run path"); if (path.back() != '\\') diff --git a/core/relinker/relinker/tests/test_windows_runpath.py b/core/relinker/relinker/tests/test_windows_runpath.py new file mode 100644 index 000000000..44db3f9bd --- /dev/null +++ b/core/relinker/relinker/tests/test_windows_runpath.py @@ -0,0 +1,42 @@ +from pathlib import Path +import os +import subprocess +import sys +import tempfile + +from test_guest_intel_trampolines import main_fixture +from test_windows_import_modules import executable, provider + + +def main(): + relinker = Path(sys.argv[1]).resolve() + with tempfile.TemporaryDirectory(prefix="anyps5-windows-runpath-") as directory: + work = Path(directory) + seed = work / "seed" + (seed / "prx").mkdir(parents=True) + (seed / "prx" / "a.prx").write_bytes(provider(77)) + source = seed / "input.elf" + source.write_bytes(main_fixture()) + result = subprocess.run([str(relinker), "--windows", str(source), str(seed / "output.exe")], + capture_output=True, text=True, timeout=20) + assert result.returncode == 0, (result.stdout, result.stderr) + library = (seed / "app0" / "prx" / "a.prx.guest.prx").read_bytes() + + for index, runpath in enumerate(("$ORIGIN", "$ORIGIN/", "$ORIGIN\\", "$ORIGIN/.", ".")): + case = work / str(index) + case.mkdir() + (case / "a.prx").write_bytes(library) + source = case / "input.elf" + source.write_bytes(executable("a.prx")) + output = case / "output.exe" + result = subprocess.run([str(relinker), "--windows", "--skip-sce-module", "--rpath", runpath, + str(source), str(output)], capture_output=True, text=True, timeout=20) + assert result.returncode == 0, (runpath, result.stdout, result.stderr) + if os.name == "nt": + executed = subprocess.run([str(output)], cwd=work, capture_output=True, text=True, timeout=20) + assert executed.returncode == 77, (runpath, executed.returncode, executed.stdout, executed.stderr) + print("Windows runpath tests passed") + + +if __name__ == "__main__": + main()