
新工具将Windows x64程序静态重编译为Apple Silicon原生应用
来源标题:Show HN: Static recompiler that runs Windows x64 on Apple Silicon
一个静态重编译器可将真实的Windows x86-64 PE二进制文件转换为ARM64 Mach-O可执行文件,运行时不做指令级模拟。实测PuTTY Plink 0.83输出与Wine+Rosetta逐字节一致,速度快6.20倍,内存占用低68.9%。PuTTY GUI、jq 1.8.2和ripgrep 14.1.1也已成功运行。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
一个静态重编译器,可将真实的 Windows x86-64 PE 二进制文件转换为原生 Apple Silicon(ARM64)Mach-O 可执行文件。它提前将原始机器码提升为 LLVM IR,并为 macOS 编译该 IR;运行时对提升后的代码没有指令级模拟。
PuTTY Plink 0.83,原生运行。原始 Windows 版本通过完整的 CRT 启动、参数解析、标准输出和关闭流程运行 -V。输出与 Wine + Rosetta 下的原始二进制逐字节一致,速度快 6.20 倍(42.31 ms 对 262.23 ms),内存占用小 68.9%(5.51 MB 对 17.74 MB RSS)。
PuTTY 0.83 GUI。原始 Windows 版本渲染其配置对话框,并打开 raw 和 SSH 终端会话(混合 NTRU Prime / Curve25519 密钥交换、Ed25519 公钥登录、AES-256)。
Plink over SSH。密钥交换、公钥登录、远程命令和退出状态 0,针对 OpenSSH。
jq 1.8.2。运行真实工作负载;已针对上游 macOS 构建验证 stdin、文件输入、Unicode 文件名、排序、正则和错误处理。
ripgrep 14.1.1。完成单线程递归搜索,匹配项和退出状态与 Wine 一致。
运行时 DLL 加载。LoadLibrary、命名导出、回调、线程局部存储和卸载,在主线程和工作线程上。Wine 自带的 ntdll、kernelbase、ucrtbase、user32、gdi32、comctl32 和 ws2_32 作为普通 guest DLL 被提升。
当前限制
这不是一个通用的“运行任何 Windows 二进制”工具。
全分辨率视频(1080p MP4)。PuTTY 窗口是提升后程序运行的截图,SSH 窗口前的等待被缩短。Plink 终端由二进制的真实输出渲染。
两个终端窗口中的文本由测试服务器(本地 OpenSSH 服务器和本地 TCP 服务器)发送。
从 Windows x86-64 到 Apple Silicon 的静态重编译充满边缘情况和未文档化的运行时行为。WAR_STORIES.md 详细记录了失败案例以及每个案例的解决方式:
Plink -V(原生)
在 Apple Silicon 上,使用优化的静态 ARM64 Mach-O,每种变体测量 30 次(2 次预热后):
重编译的 ARM64 可执行文件和 Wine + Rosetta 的 stdout 逐字节一致,退出状态均为 0。
在 Apple M1 上测量,每种变体运行五次,一次预热后,机器上还有其他工作运行。“冷”运行从停止的 wineserver 开始,因此其启动时间包含在两列中;“热”运行发现它已在运行。内存是程序自身进程的常驻大小。
冷启动主要由 wineserver 启动主导,两种变体都需支付此成本,因此提升后的程序在那里仅略快或持平。服务器运行时,提升后的 SSH 命令大约快一倍半。内存使用高 1.6 到 2 倍;这尚未调查。程序自身的代码以 -O2 编译(设置 ARM64_RECOMPILER_PROGRAM_OPT 可更改),--trace 每条 guest 指令花费一次存储。
在装有 Clang 和 Python 的 Apple Silicon Mac 上,从仓库根目录运行。要设置 Python 环境:
python3 -m venv work/venv work/venv/bin/python3 -m pip install -r recompiler/requirements.txt
- 运行回归测试套件
演练 11,121 个算术和控制流指令排列、原子 lock cmpxchg、数据重定位和控制台测试:
PYTHON="$PWD/work/venv/bin/python3" recompiler/run.sh
它还运行虚拟内存测试(test_mmap.c)和七个 fixture:
fixture 在安装 Wine 时与 Wine 比较(recompiler/setup_wine.py,或 WINE/WINEPREFIX)。MSVC 案例需要 xwin SDK(XWIN_SDK)和 LLVM clang-cl/lld-link。没有它们时会打印 SKIP,或者如果 REQUIRE_MSVC=1 则失败。
重编译原始 plink.exe 并验证 -V 输出和退出状态:
PYTHON="$PWD/work/venv/bin/python3"
recompiler/test_plink_startup.sh "$PWD/work/corpus/plink.exe"
使用自动 .pdata 函数发现,这在第 0 次尝试时成功,打印 plink: Release 0.83 并以状态 0 退出。
需要匹配的 LLVM 22 Clang 和 llvm-link。如果 LLVM 安装在 /opt/homebrew/opt/llvm@22/bin 之外,请将 LLVM_BIN 设置为其 bin 目录。一致性测试以 macOS ARM64 jq 1.8.2 发布版为参考。
PYTHON="$PWD/work/venv/bin/python3"
recompiler/build_jq.sh work/corpus/jq.exe work/build/jq-arm64
curl -fsSL https://github.com/jqlang/jq/releases/download/jq-1.8.2/jq-macos-arm64
-o work/build/jq-reference
chmod +x work/build/jq-reference
work/venv/bin/python3 recompiler/test_jq.py work/build/jq-arm64 work/build/jq-reference
该测试检查 stdin、文件输入、Unicode 文件名、排序、正则、格式错误的 JSON 和 jq 的 -e 行为的 stdout、stderr 和退出码。
fixture 构建一个 Windows EXE 和 DLL,将它们重编译为 ARM64,并检查运行时加载、命名导出、回调、线程局部存储以及主线程和工作线程上的卸载:
PYTHON="$PWD/work/venv/bin/python3"
recompiler/fixtures/dynamic_dll/test.sh
- 跟踪 corpus 二进制的启动
跟踪原生执行并检查其他 Windows 二进制的停止点:
jq 1.8.2
$PWD/work/venv/bin/python3 recompiler/trace_callbacks.py --max-attempts 1 work/corpus/jq.exe --version
ripgrep 14.1.1
$PWD/work/venv/bin/python3 recompiler/run_exe.py --trace work/corpus/rg.exe --threads 1 --no-config --no-heading --sort path -n PATTERN DIRECTORY
- 运行 Windows GUI 或网络程序(托管模式)
托管模式需要 x86-64 Wine 11.0 安装(setup_wine.py 会在 work/wine 下放置一个)以及为 arm64 原生构建的 Wine unix 侧。构建一次(需要 Xcode 的 clang、Homebrew LLVM、FreeType 和 bison 3 或更新版本):
recompiler/wine-host/build.sh "$PWD/work/wine-host"
然后 lift_app.py 提升一个程序及其所需的 Wine DLL,并可以启动它。它跟随静态导入、导出转发器和延迟导入一层深度:
Wine 的任务管理器:选项卡控件、列表视图、状态栏、工作线程。
work/venv/bin/python3 recompiler/wine-host/lift_app.py \
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。