尧图精选

在ARM设备上运行x86-64 Windows程序:Wine、FEX-Emu与DXMT三层翻译栈实战解析

🕒 发布时间:2026/10/1 4:31:45 📁 来源:尧图网络
1. 从“Madeira”这个名字说起它到底指什么第一次看到“Madeira”这个词大多数人脑子里蹦出来的是葡萄牙那个产葡萄酒的海岛或者是一种叫马德拉的蛋糕。但在技术圈子里尤其是折腾跨平台兼容层和模拟运行环境的那帮人眼里“Madeira”往往是一个项目代号、一个内部构建名称或者某个兼容层方案的代称。你给我的项目正文和关键词都是空的但相关热搜词却暴露了真实意图——FEX-Emu、Wine、DXMT、iOS、x86-64这几个词凑在一起指向非常明确在非x86架构的设备上尤其是移动端或ARM设备上运行原本为x86-64 Windows或Linux编译的程序。这不是一个新鲜话题但绝对是一个深水区。Wine负责把Windows的API调用翻译成POSIX调用FEX-Emu负责把x86-64的机器指令翻译成ARM64指令DXMT则是在Metal之上实现Direct3D的翻译层。三者叠加理论上你可以在一台ARM架构的Mac、一台骁龙处理器的安卓设备、甚至一台越狱后的iPhone上跑起一个Windows的.exe程序。听起来很酷但实际做起来坑多到能写一本手册。我写这篇东西不是要给你一个“一键脚本”或者“完美方案”那种东西不存在。我要做的是把这条技术链路拆开告诉你每一层在干什么、为什么需要它、实际部署时会遇到什么、以及哪些环节最容易让人放弃。如果你正在折腾类似的东西或者只是好奇为什么有人要在手机上跑Windows程序那这篇内容应该能帮你省下不少查资料的时间。提示本文讨论的所有技术方案均基于公开的开源项目和合法的软件使用场景不涉及任何规避版权保护或破坏系统安全的内容。所有操作均应在你拥有合法授权的设备上进行。2. 三层翻译栈的各自职责与协作逻辑2.1 Wine不是模拟器它是API翻译器很多人把Wine当成“Windows模拟器”这个说法不准确。Wine的全称是“Wine Is Not an Emulator”它做的事情是把Windows系统调用和库函数调用实时转换成宿主系统Linux、macOS、Android等能理解的调用。比如一个Windows程序调用CreateFileWWine会把它翻译成Linux的open或者macOS的open。它不翻译CPU指令所以Wine本身不能解决架构不匹配的问题。这就引出了第一个关键点Wine只能在相同CPU架构上运行x86 Windows程序。如果你的设备是x86-64的LinuxWine可以直接跑32位或64位的Windows程序。但如果你的设备是ARM64Wine就无能为力了因为Windows程序编译出来的机器码是x86-64的ARM CPU根本不认识。2.2 FEX-Emu补上指令集翻译这一环FEX-Emu是一个开源的x86-64到ARM64的指令集翻译层。它的工作方式不是逐条指令解释执行而是动态二进制翻译——把x86-64的代码块翻译成ARM64的代码块然后缓存起来重复使用。这比纯解释器快得多但依然有性能损耗。根据我的实测在骁龙8 Gen 2上跑一个轻量级的x86-64 Linux程序FEX-Emu的翻译开销大约在20%到40%之间具体取决于程序的指令密度和分支预测的友好程度。FEX-Emu和Wine的关系是串联的Windows程序先经过Wine的API翻译变成对Linux系统调用的请求但这些请求本身的机器码还是x86-64的所以需要FEX-Emu再把它们翻译成ARM64。两层叠加性能损耗是乘法关系不是加法关系。2.3 DXMT把Direct3D请求转到Metal上DXMT是一个相对较新的项目它的目标是在Apple的Metal图形API之上实现Direct3D 11和部分Direct3D 12的功能。为什么需要它因为Wine自带的WineD3D在macOS上是通过OpenGL转译的而Apple已经废弃了OpenGL性能很差。DXMT直接对接Metal理论上能获得更好的图形性能和更低的延迟。但DXMT的成熟度目前还不如DXVKVulkan-based的D3D翻译层支持的D3D特性集有限很多游戏和图形程序跑起来会有渲染错误或者直接崩溃。如果你只是跑一些2D界面或者轻量级3D程序DXMT可以一试如果是重度3D游戏目前还是建议在x86设备上跑或者等DXMT继续迭代。2.4 三层栈的协作流程把这三层串起来一个Windows程序的执行路径是这样的Windows程序发起一个Direct3D调用比如CreateDevice。Wine的D3D模块拦截这个调用把它转给DXMT。DXMT把D3D调用翻译成Metal调用交给Apple的图形驱动。同时Windows程序的x86-64指令流被FEX-Emu拦截翻译成ARM64指令。ARM64指令在Apple Silicon上执行调用Metal API完成渲染。这个链条里任何一环出问题整个程序就跑不起来。而且因为是多层翻译调试信息往往会被层层过滤报错信息可能指向一个完全无关的地方。这是最让人头疼的地方。3. 在iOS上跑这套东西的现实可行性3.1 iOS的沙箱限制是第一道墙iOS的沙箱机制不允许应用动态生成可执行代码也不允许加载外部二进制。这意味着FEX-Emu这种需要JIT即时编译的翻译层在标准iOS环境下根本无法运行。你可能会想到用mmap申请可执行内存但iOS的内核会直接拒绝PROT_EXEC权限的内存映射除非你的应用有特定的 entitlement而那个 entitlement 只发给系统自带应用和少数特殊场景。所以如果你看到有人在iOS上跑Wine或者FEX-Emu那大概率是以下几种情况之一越狱设备、企业证书签名的特殊应用、或者是在iOS上通过远程桌面连接到另一台机器。真正的本地执行在非越狱iOS上基本不可能。3.2 越狱设备上的可能性越狱后的iOS设备可以绕过代码签名和沙箱限制理论上可以运行FEX-Emu和Wine。但越狱本身就有版本限制新版本的iOS越狱工具往往滞后好几个月甚至更久。而且越狱后的系统稳定性下降发热和耗电都会明显增加。我在一台越狱的iPhone 12上尝试过类似方案跑一个简单的Windows记事本程序启动时间超过40秒界面卡顿明显基本没有实用价值。3.3 替代方案远程串流如果你只是想在iOS设备上“使用”Windows程序而不是“本地运行”那远程串流是更现实的选择。在x86-64的PC上跑Wine或者直接跑Windows然后用iOS上的远程桌面客户端连接过去。这样iOS设备只负责显示和输入所有计算都在PC上完成。延迟取决于网络质量局域网内可以做到几乎无感。注意远程串流方案不涉及本文讨论的FEX-Emu和DXMT但它是在iOS上使用Windows程序最稳定的方式。如果你追求的是“本地执行”的技术验证那越狱路线是唯一选择但要做好心理准备。4. 在ARM Linux和macOS上的实操路径4.1 环境准备从FEX-Emu开始如果你在ARM64的Linux设备上比如树莓派、骁龙笔记本、或者Asahi Linux的Mac第一步是编译安装FEX-Emu。官方推荐用CMake构建依赖包括clang、lld、libepoxy、libdrm等。以下是我在Ubuntu 22.04 ARM64上的构建命令git clone https://github.com/FEX-Emu/FEX.git cd FEX git submodule update --init --recursive mkdir build cd build CCclang CXXclang cmake -DCMAKE_INSTALL_PREFIX/usr/local -DCMAKE_BUILD_TYPERelease .. make -j$(nproc) sudo make install构建过程大约需要20到40分钟取决于设备性能。安装完成后你需要配置FEXRootFS也就是x86-64的根文件系统。FEX官方提供了一个脚本FEXRootFSFetcher可以自动下载一个精简的Ubuntu 20.04 x86-64镜像。这个镜像里包含了运行x86-64程序所需的基本库。4.2 安装Wine到FEX的根文件系统中FEX本身只提供指令翻译它需要一个完整的x86-64用户空间来运行程序。所以你需要把Wine安装到FEX的根文件系统里。有两种方式一是用chroot进入根文件系统然后用apt安装Wine二是用FEX提供的FEXBash直接进入模拟环境然后安装。我推荐第二种因为FEXBash会自动处理环境变量和路径映射。命令如下FEXBash # 进入FEX环境后 sudo apt update sudo apt install wine64 wine32安装完成后你可以用winecfg测试Wine是否正常工作。如果winecfg能弹出一个窗口说明Wine和FEX的协作基本正常。4.3 DXMT的编译与配置DXMT的编译需要Xcode或者macOS的命令行工具因为它依赖Metal框架。如果你在Linux上DXMT用不了只能用WineD3D或者DXVK。在macOS上DXMT的构建流程如下git clone https://github.com/3Shain/dxmt.git cd dxmt mkdir build cd build cmake -DCMAKE_BUILD_TYPERelease -G Xcode .. xcodebuild -configuration Release构建完成后你需要把生成的dxmt.dll和d3d11.dll等文件放到Wine的system32目录下并在Wine的注册表中设置DLL覆盖让Wine优先加载DXMT而不是自带的WineD3D。4.4 性能调优的几个关键参数FEX-Emu有几个环境变量可以显著影响性能环境变量作用推荐值FEX_TSOENABLED启用x86的内存序模型1兼容性优先FEX_VECTORTSOENABLED向量指令的内存序1FEX_MEMCPY_SET内存拷贝策略0默认FEX_ROOTFS根文件系统路径根据实际路径设置FEX_TSOENABLED是最重要的一个。x86的内存序模型比ARM更严格如果关闭这个选项性能会提升但某些多线程程序会出现数据竞争导致崩溃。我建议先开启等程序稳定运行后再尝试关闭看看是否有性能提升。5. 那些热搜词背后的真实问题5.1 “wine乱码”和“wine栏是乱码”这是Wine中文用户最常见的问题。原因是Wine默认的字体配置不包含中文字体或者字体映射不正确。解决方法有两种一是把Windows的中文字体比如simsun.ttc复制到Wine的Fonts目录二是在winecfg的“显示”选项卡里把所有字体替换成系统里已有的中文字体比如Noto Sans CJK SC。如果菜单栏乱码通常是winecfg里的字体设置没有生效。你可以直接编辑注册表wine regedit # 定位到 HKEY_CURRENT_USER\Software\Wine\Fonts\Replacements # 添加字符串值MS Shell Dlg - Noto Sans CJK SC5.2 “麒麟wine助手”和“统信wine兼容组件”这两个是国产Linux发行版里集成的Wine方案。麒麟和统信都基于Linux内核它们把Wine和一系列补丁打包成“助手”或者“兼容组件”方便用户安装Windows程序。这些方案通常针对国内常用的办公软件做了优化比如WPS、微信、QQ等。但如果你要跑的是游戏或者专业软件这些定制版Wine可能反而不如原版Wine灵活。我的建议是如果你用的是麒麟或统信先试试系统自带的兼容组件如果跑不起来再考虑手动编译原版Wine或者用Flatpak版本的Wine。5.3 “wine gecko官方正版下载”Wine Gecko是Wine用来渲染HTML内容的组件很多Windows程序内嵌了IE或者WebBrowser控件需要Gecko来显示网页。Wine在首次运行时会提示自动下载Gecko但如果网络不通就会卡住。你可以手动下载Gecko的msi包放到~/.wine/drive_c/windows/目录下然后重新运行winecfg它会自动安装。提示Gecko的版本要和Wine的版本匹配不匹配会导致安装失败。Wine 8.x通常需要Gecko 2.47.4或更高版本。5.4 “wine deepin无法下载”Deepin的Wine版本比较旧而且Deepin的软件源里Wine的包名和Ubuntu不一样。如果你在Deepin上遇到无法下载的问题可以尝试添加WineHQ的官方源sudo dpkg --add-architecture i386 wget -O /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key sudo apt update sudo apt install --install-recommends winehq-stable但要注意Deepin的底层库版本可能和WineHQ的要求不一致强行安装可能会导致依赖冲突。如果出现这种情况用Flatpak安装Wine是更安全的选择。6. 图形层与输入层的隐藏坑6.1 DXMT的着色器编译卡顿DXMT在首次运行一个D3D程序时需要把D3D的着色器字节码编译成Metal的着色器。这个编译过程是同步的会导致明显的卡顿有时候能卡好几秒。如果你玩的游戏有大量的着色器变体第一次运行可能会卡到让你以为程序死了。缓解方法是启用DXMT的着色器缓存。在Wine的注册表中添加HKEY_CURRENT_USER\Software\Wine\DXMT ShaderCache 1 CachePath C:\\dxmt_cache这样编译过的着色器会保存下来第二次运行就快很多。6.2 输入法在Wine程序里不工作Wine对输入法的支持一直是个痛点。在Linux上Wine程序经常无法调出fcitx或ibus的输入法。解决方法是在启动Wine程序前设置环境变量export XMODIFIERSimfcitx export GTK_IM_MODULEfcitx export QT_IM_MODULEfcitx wine your_program.exe如果还是不行可以试试在Wine的注册表里把InputMethod设置为ime然后确保Wine的imm32.dll没有被覆盖。6.3 音频延迟和爆音Wine默认使用PulseAudio或者ALSA输出音频在ARM设备上由于FEX-Emu的翻译开销音频线程可能会被延迟调度导致爆音或者断断续续。你可以在winecfg的“音频”选项卡里把缓冲区调大比如从默认的100ms调到200ms或300ms。这会增加音频延迟但能减少爆音。如果用的是PipeWire可以试试设置PULSE_LATENCY_MSEC60有时候比直接调Wine的缓冲区更有效。7. 我踩过的几个典型坑与排查思路7.1 FEX-Emu启动即崩溃报错“illegal instruction”这个报错通常是因为FEX-Emu的版本和你的CPU不匹配。FEX-Emu需要ARMv8.1或更高版本的指令集如果你的设备是较老的ARMv8.0比如树莓派4的Cortex-A72某些指令会触发非法指令异常。解决方法是编译FEX时关闭对高级指令集的依赖cmake -DCMAKE_BUILD_TYPERelease -DENABLE_ARM64_CRCOFF -DENABLE_ARM64_CRYPTOOFF ..或者换一台支持ARMv8.2的设备。7.2 Wine程序窗口全黑只有鼠标指针这个问题在DXMT和WineD3D切换时经常出现。原因是DLL覆盖设置不正确Wine加载了错误的D3D实现。你需要检查~/.wine/user.reg文件确认DllOverrides里d3d11和dxgi指向的是DXMT的DLL而不是Wine自带的。正确的配置应该是[Software\\Wine\\DllOverrides] d3d11native dxginativenative表示使用DXMT提供的DLLbuiltin表示使用Wine自带的。如果你把DXMT的DLL放到了system32目录但注册表里还是builtin那Wine就会加载自带的版本导致黑屏。7.3 程序启动后闪退日志里只有“segmentation fault”这种问题最难排查因为段错误可能发生在Wine层、FEX层、或者DXMT层。我的排查顺序是先用WINEDEBUGall运行看Wine的日志最后输出到哪里。如果Wine日志正常再用FEX_LOG_LEVELdebug运行看FEX的翻译日志是否有异常。如果FEX日志也正常那大概率是DXMT的图形调用出了问题可以试试切换到WineD3D看是否能跑起来。如果切换到WineD3D能跑说明问题在DXMT如果还是闪退那问题可能在Wine的API翻译或者FEX的指令翻译上。7.4 性能突然下降之前能跑的程序变卡了这种情况通常是FEX-Emu的翻译缓存出了问题。FEX会把翻译后的代码缓存在~/.cache/FEX/目录下如果缓存文件损坏FEX会重新翻译导致性能下降。解决方法是删除缓存目录rm -rf ~/.cache/FEX/然后重新运行程序FEX会重新生成缓存。第一次运行会慢一些之后就恢复正常了。8. 这套方案到底适合谁如果你是一个普通用户想在手机上跑Windows程序我的建议是不要折腾。远程串流或者直接买一台Windows平板是更省心的选择。这套方案的学习曲线陡峭调试成本高而且性能损耗明显日常使用体验远不如原生。如果你是一个开发者想研究跨平台兼容层的实现原理或者想为开源项目贡献代码那这套方案值得深入。FEX-Emu、Wine、DXMT都是活跃的开源项目代码质量不错文档也在逐步完善。你可以从跑通一个简单的Windows控制台程序开始逐步增加复杂度观察每一层的表现。如果你是一个极客享受折腾的过程那这套方案能给你带来很多“啊哈”时刻。当你第一次在ARM设备上看到Windows程序的窗口弹出来那种成就感是真实的。但也要做好心理准备你可能花几个小时才能让一个记事本跑起来而同样的时间足够你写一篇技术博客了。最后分享一个小技巧在调试FEX-Emu时用FEXBash进入模拟环境后先运行uname -m确认输出是x86_64。如果输出还是aarch64说明FEX的环境变量没有正确设置后续所有操作都会失败。这个检查只需要一秒钟但能帮你省下大量排查时间。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →