Rust 官方对 arm64ec-pc-windows-msvc 目标的支持:在 AArch64 Windows 11 上构建混合架构应用
【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust
arm64ec-pc-windows-msvc是 Rust 编译器(rustc)官方支持的一个 Tier 2 目标平台,用于在 AArch64(ARM64)版 Windows 11 上构建Arm64EC(Emulation Compatible,仿真兼容)应用——这类应用以混合架构(AArch64 指令集 + x86_64 进程模型)运行。本文以 平台支持文档 为主体,结合 rustc 源码中的目标定义、ABI 实现与内联汇编约束,完整讲解该目标的能力边界、环境要求、构建方式与代码复用决策,读完即可上手配置工具链并写出可运行的 Arm64EC 程序。
Arm64EC 与arm64ec-pc-windows-msvc:一个"仿真兼容"的混合架构目标
Arm64EC 是微软在 AArch64 版 Windows 11 上推出的应用兼容技术。它允许应用程序同时包含 AArch64 原生代码与 x86_64 仿真代码:整个进程以 x86_64 应用的形态与操作系统及其他 DLL 交互,而自身关键路径(如性能敏感模块)使用 AArch64 指令集执行,从而在 ARM 设备上获得接近原生性能的同时保持对 x86_64 生态的二进制兼容。
rustc 为这一形态提供了独立的编译目标arm64ec-pc-windows-msvc。该目标在 平台支持文档 中被标记为Tier 2,意味着它由社区维护者(@dpaoliello)负责跟进,rustc 官方发布流程保证其工具链可用,但属于"保证可构建、不保证所有修复及时落地"的层级。
该目标可产出的工件包括:
- Arm64EC 静态库与动态库:可在 AArch64 Windows 11 设备上直接加载运行;
- Arm64EC 可执行文件:与 AArch64 原生进程不同,它以 x86_64 进程身份运行,从而可以加载 x86_64 的 DLL 与插件;
- 可供 Arm64X 链接的静态库:Arm64EC 静态库可以进一步链接进Arm64X动态库和可执行文件。Arm64X 是同时携带 AArch64 与 x86_64 两份代码入口的二进制形态,系统根据运行进程的架构自动选择加载哪一份,这一特性使单个安装包可以同时服务原生 ARM 进程与仿真 x86_64 进程。
环境要求:LLVM 18+、Visual Studio 2022 与 Windows 11 SDK
构建arm64ec-pc-windows-msvc目标并非零依赖,官方文档明确了三点硬性要求:
后端必须是 LLVM 18 或以上。Arm64EC 依赖 LLVM 的混合目标代码生成能力,且不同小版本修复了不同问题:
- 18.1.0:首次加入对 Arm64EC 的初始支持;
- 18.1.2:修复导入库(import library)生成问题,这是
raw-dylib支持所必需的; - 18.1.4:修复部分在
compiler_builtins中实现的 intrinsics 的链接问题。
从源码结构看,rustc 将 Arm64EC 作为 LLVM 后端的
llvm_target字符串直接透传(见下文目标定义一节),因此 LLVM 版本下限直接决定了该目标的可用性。Visual Studio 2022(或以上),且必须勾选"ARM64/ARM64EC built tools"组件——该组件提供 Arm64EC 所需的 MSVC 链接器与库。
Windows 11 SDK:Arm64EC 仅在 AArch64 Windows 11 上受支持,SDK 需配套安装。
rustc 中的目标定义:从源码看 Arm64EC 的实现要点
要理解该目标的行为,最好的入口是它的规范定义文件 arm64ec_pc_windows_msvc.rs。该文件完整定义了 rustc 眼中的 Arm64EC:
pub(crate) fn target() -> Target { let mut base = base::windows_msvc::opts(); base.max_atomic_width = Some(128); base.features = "+v8a,+neon".into(); add_link_args( &mut base.late_link_args, LinkerFlavor::Msvc(Lld::No), &["/machine:arm64ec", "softintrin.lib"], ); // Microsoft recommends enabling frame pointers on Arm64 Windows. base.frame_pointer = FramePointer::NonLeaf; Target { llvm_target: "arm64ec-pc-windows-msvc".into(), metadata: TargetMetadata { description: Some("Arm64EC Windows MSVC".into()), tier: Some(2), host_tools: Some(false), std: Some(true), }, pointer_width: 64, data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32" .into(), arch: Arch::Arm64EC, options: base, } }从这份定义可以提炼出多个关键实现事实:
- 架构标识:
arch被设为Arch::Arm64EC,而pointer_width为 64。在 spec/mod.rs 中,Arch::Arm64EC被映射为Architecture::Aarch64加上object::SubArchitecture::Arm64EC——也就是说,生成的目标文件底层是 AArch64 对象格式,但带有 Arm64EC 子架构标记,这正是链接器能识别并生成混合二进制的关键。 - 指令特性:
features = "+v8a,+neon",即目标默认启用 ARMv8-A 基础指令集与 NEON 向量扩展,与 AArch64 原生目标保持一致。 - 链接参数:通过
add_link_args为 MSVC 链接器追加/machine:arm64ec并链接softintrin.lib(软件整数 intrinsics 支持库)。 - 帧指针:
frame_pointer = FramePointer::NonLeaf——微软要求 Arm64 Windows 上的非叶子函数必须维护帧指针(x29),以便 ETW 等系统服务进行快速栈回溯,rustc 因此在非叶子函数中强制生成帧指针。 - 原子宽度:
max_atomic_width = Some(128),即支持 128 位原子操作。 - 元数据:Tier 2、
host_tools: false(不能作为构建宿主)、std: true(提供标准库)。
代码复用决策:Arm64EC 到底算 x86_64 还是 AArch64?
在写#[cfg(target_arch = ...)]条件代码时,开发者最常见的困惑是:Arm64EC 的target_arch是arm64ec,那架构相关的既有代码该按 x86_64 还是 AArch64 复用?官方文档给出了一个非常实用的思维模型:
把 Arm64EC 想成一个"碰巧使用 AArch64 指令集(有一些注意事项)且拥有完全自定义 ABI 的 x86_64 进程"。
据此,按场景分三种情况处理:
与系统、进程和 DLL 的交互:按 x86_64 处理
Arm64EC 进程对外表现为 x86_64 进程,因此凡是涉及"身份"的代码都应走 x86_64 路径:
- 寄存器上下文与栈回溯:例如在
backtrace库中,应使用 x86_64 版本的CONTEXT结构和RtlVirtualUnwind函数,因为异常展开发生在一个 x86_64 语义的进程中; - DLL 搜索路径:如果应用需要配置路径去加载插件或附加组件,应复用x86_64 版本的路径,而不是 AArch64 路径——因为 Arm64EC(即 x86_64)进程无法加载原生 AArch64 的 DLL,只能加载 x86_64 或 Arm64EC 的 DLL。
内建函数与 SIMD:按 AArch64 处理
Arm64EC 使用 AArch64 指令集执行计算,因此 CPU intrinsics 应选用 AArch64 版本。Rust 生态中的 portable-simd 与 stdarch 两个子项目均有针对 Arm64EC 的适配提交,直接在 AArch64 intrinsics 上启用该目标。
内联汇编:大量注意事项
AArch64 汇编对 Arm64EC 可能部分可复用,但存在许多限制。rustc 在内联汇编的寄存器分配器中直接落实了这些约束,见 asm/aarch64.rs 中restricted_for_arm64ec的实现:
fn restricted_for_arm64ec( arch: InlineAsmArch, _suggest: &mut dyn FnMut(TargetSpecError), ) -> Result<(), TargetSpecError> { if arch == InlineAsmArch::Arm64EC { Err("x13, x14, x23, x24, x28, v16-v31, p*, ffr cannot be used for Arm64EC") } else { Ok(()) } }也就是说,在 Arm64EC 目标上使用内联汇编时,以下寄存器不可使用:x13、x14、x23、x24、x28、向量寄存器v16–v31、谓词寄存器p0–p15以及ffr。这些寄存器被保留用于 Arm64EC 的混合调用机制(thunk、调用检查等),用户汇编代码一旦触碰即报错。
官方文档还概括了其余几个关键差异(详见微软的 Arm64EC ABI 文档,此处转述要点):
- 寄存器子集:Arm64EC 只使用 AArch64 寄存器的一个子集;
- 名称修饰:Arm64EC 使用与 AArch64 不同的符号名称修饰(mangling)方案;
- 入口/出口 thunk:部分函数必须生成额外的进入/离开 thunk,以完成 AArch64 代码与 x86_64 仿真代码之间的调用切换;
- 间接调用:必须通过调用检查器(call checker)完成;
- 安全机制:控制流保护(CFG)与栈检查(stack check)使用的辅助函数与 AArch64 原生不同。
自定义 ABI 的两个源码实证
"完全自定义 ABI"并非虚言,rustc 中有两处专门为 Arm64EC 定制的 ABI 逻辑:
1. C 可变参数遵循 MS x64 ABI。在 callconv/aarch64.rs 中,rustc 明确处理了 Arm64EC 的 C 可变参数:可变参数部分(即idx >= fixed_count之后)不再按 AArch64 规则传参,而是遵循 MS x64 ABI 的规则——"任何超过 8 字节、或尺寸不是 1/2/4/8 字节的参数,必须按引用传递",对应实现是arg.make_indirect():
// On Arm64EC the variadic portion of a c-variadic call follows the MS x64 ABI: // "Any argument that doesn't fit in 8 bytes, or is not 1, 2, 4, or 8 bytes, must // be passed by reference". let is_arm64ec = cx.target_spec().arch == Arch::Arm64EC; // ... if is_arm64ec && c_variadic && idx >= fixed_count { let size = arg.layout.size.bytes(); if size > 8 || !size.is_power_of_two() { arg.make_indirect(); continue; } }2. 符号修饰规则。在 symbol_export.rs 中,Arm64EC 与 x86 家族一样使用符号修饰(decoration),但 Arm64EC 的#修饰只作用于函数(Text 段)符号:
// Only functions are decorated for arm64ec. Arch::Arm64EC if export_kind == SymbolExportKind::Text => Some('#'), // Only x86/64 and arm64ec use symbol decorations.这与 AArch64 原生目标(不使用#修饰)截然不同,再次印证了"混合 ABI"的定位。
构建带 Arm64EC 支持的 Rust 编译器
如果你需要自己从源码构建一个支持arm64ec-pc-windows-msvc的 Rust 工具链,只需在bootstrap.toml的[build]段把目标加入target列表:
[build] target = ["arm64ec-pc-windows-msvc"]仓库根目录提供了参考配置模板 bootstrap.example.toml,可以对照其中的[build] target写法扩展。完成配置后,使用./x.py build(仓库内置的 x.py 构建脚本)即可构建出包含该目标的编译器与标准库。
构建 Rust 程序:rustup 开箱即用
对普通用户而言,不需要任何特殊配置。arm64ec-pc-windows-msvc目标随官方分发渠道(rustup)一起发布,安装方式与其他目标一致:
rustup target add arm64ec-pc-windows-msvc cargo build --target arm64ec-pc-windows-msvc前提是已经安装了满足上文要求的 Visual Studio 2022(含 ARM64/ARM64EC 构建工具)与 Windows 11 SDK,rustc 会调用 MSVC 链接器完成 Arm64EC 混合二进制的链接。
测试
该目标的测试需要在AArch64 Windows 11 设备上运行——因为 Arm64EC 二进制只能在该硬件平台上执行。对于 CI 场景,可以准备 ARM64 物理机或云上的 AArch64 Windows 实例,将编译产物拷入后执行标准库与集成测试套件。
交叉编译工具链与 C 代码
Arm64EC 项目往往需要混合编写 Rust 与 C/C++。C 代码可以使用面向 ARM64 的 MSVC 或 Clang 工具链来构建,关键在于编译与链接阶段都要显式声明 Arm64EC:
编译(cl.exe):
cl /arm64EC /c ...链接(link.exe):
link /MACHINE:ARM64EC ...与 rustc 目标定义中add_link_args(..., &["/machine:arm64ec", "softintrin.lib"])的做法相互印证:链接阶段必须指定/MACHINE:ARM64EC,让链接器生成带有 Arm64EC 子架构标记的输出,并与 Rust 侧保持一致的工具链参数。
小结
arm64ec-pc-windows-msvc是 rustc 为混合架构场景提供的 Tier 2 目标:它用 AArch64 指令集执行计算、以 x86_64 进程身份与系统交互,并采用一套完全自定义的 ABI。本文梳理了其环境要求(LLVM 18+、VS 2022、Windows 11 SDK)、rustc 源码中的目标定义与 ABI 细节(C 可变参数规则、符号修饰、内联汇编寄存器限制)、bootstrap.toml构建配置、rustup 安装方式以及 C 代码交叉编译命令。对于想要让 Windows 应用同时享受 AArch64 原生性能与 x86_64 生态兼容的团队,arm64ec-pc-windows-msvc提供了一条官方支持、可直接落地的路径;对于需要深入底层的行为细节(如哪些寄存器可用、可变参数如何传参),可直接查阅 arm64ec_pc_windows_msvc.rs、callconv/aarch64.rs 与 asm/aarch64.rs 获得第一手实现依据。
【免费下载链接】rustEmpowering everyone to build reliable and efficient software.项目地址: https://gitcode.com/GitHub_Trending/ru/rust
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考