diff --git a/tools/linuxfs/overlay/usr/local/bin/droiddeck-wine-pe b/tools/linuxfs/overlay/usr/local/bin/droiddeck-wine-pe index 7034bf301..65c3446a2 100755 --- a/tools/linuxfs/overlay/usr/local/bin/droiddeck-wine-pe +++ b/tools/linuxfs/overlay/usr/local/bin/droiddeck-wine-pe @@ -1,4 +1,5 @@ #!/usr/bin/python3 +import re from pathlib import Path @@ -75,8 +76,16 @@ def pe_has_arm64ec_metadata(path): return False +# Only x64 code and members of the same runtime family import these, so an x64 copy loads in an +# ARM64EC prefix, and games check for a newer version than Wine's builtins report. +VC_RUNTIME = re.compile(r"(msvc[pr]\d.*|vcruntime\d.*|vcomp\d*|vcamp\d.*|vccorlib\d.*|concrt\d.*|mfcm?\d.*)\.dll", + re.IGNORECASE) + + def machine_compatible(path, machines, machine=None): machine = pe_machine(path) if machine is None else machine + if machine == 0x8664 and 0xA641 in machines and VC_RUNTIME.fullmatch(Path(path).name): + return True if machine == 0x8664 and pe_has_arm64ec_metadata(path): return 0xA641 in machines return machine in machines diff --git a/tools/tests/test_game_environment.py b/tools/tests/test_game_environment.py index b1cdcedad..d6cb49582 100644 --- a/tools/tests/test_game_environment.py +++ b/tools/tests/test_game_environment.py @@ -2738,6 +2738,17 @@ class ForeignSystemDllTest(unittest.TestCase): self.assertFalse((system32 / "ucrtbase.dll").is_symlink()) self.assertEqual(0x8664, MODULE["pe_machine"](system32 / "userlib.dll")) + def test_x64_visual_cpp_runtime_in_arm64_system32_is_kept(self): + with tempfile.TemporaryDirectory() as tmp: + proton, compat, windows = self.prefix(tmp) + builtins = proton.parent / "files/lib/wine/aarch64-windows" + for name in ("msvcp140.dll", "VCRUNTIME140.dll", "msvcp_win.dll"): + (builtins / name.lower()).write_bytes(pe_image(0xAA64)) + (windows / "system32" / name).write_bytes(pe_image(0x8664)) + self.assertEqual(["system32/msvcp_win.dll (machine 0x8664)"], self.run_repair(compat, proton)) + self.assertFalse((windows / "system32/msvcp140.dll").is_symlink()) + self.assertFalse((windows / "system32/VCRUNTIME140.dll").is_symlink()) + def test_final_arm64ec_image_is_not_repaired_as_a_foreign_x64_dll(self): with tempfile.TemporaryDirectory() as tmp: proton, compat, windows = self.prefix(tmp) diff --git a/tools/tests/test_wincomponents.py b/tools/tests/test_wincomponents.py index e6ad95e2d..7423fb2bb 100644 --- a/tools/tests/test_wincomponents.py +++ b/tools/tests/test_wincomponents.py @@ -92,6 +92,18 @@ class WinComponentsTest(unittest.TestCase): self.assertEqual(names, ["ucrtbase"]) self.assertEqual(MODULE["pe_machine"](self.pfx / "system32/ucrtbase.dll"), 0x8664) + def test_x64_visual_cpp_runtime_is_placed_in_arm64_system32(self): + proton = self.proton() + self.component("vc", ["msvcp140", "vcruntime140_1"], { + "system32/msvcp140.dll": self.pe_image(0x8664), + "system32/vcruntime140_1.dll": self.pe_image(0x8664), + }) + self.pick("vc") + names, _ = self.apply(proton) + self.assertEqual(names, ["msvcp140", "vcruntime140_1"]) + self.assertEqual(MODULE["pe_machine"](self.pfx / "system32/msvcp140.dll"), 0x8664) + self.assertEqual(MODULE["pe_machine"](self.pfx / "system32/vcruntime140_1.dll"), 0x8664) + def test_compatible_copy_keeps_override_when_other_architecture_copy_is_skipped(self): proton = self.proton() self.component("vc", ["ucrtbase"], {