> 文档中心 > Win11 ARM64深度解析

Win11 ARM64深度解析

【x86和x64模拟基本原理】

x86模拟从Win10 1709 Build 16299就开始支持了,它使用xtajit.dll即时翻译器和WOW64机制,SysWOW64包含了完整的WOW64运行时,部分系统DLL编译为可选的CHPE版本并放在SyChpe32下面,CHPE版本包含混合的x86/ARM64机器码,可以加速系统文件的执行

x64模拟从Win11 21H2 Build 22000(Win10 Insider Build 21277)开始支持,它使用xtajit64.dll即时翻译器和变色龙PE机制,System32大部分用户态系统文件改成了ARM64X版本,ARM64X版本复合了ARM64 Native版本和ARM64EC版本,ARM64EC版本包含混合的x64/ARM64机器码,以支持x64程序运行

【Visual C++支持编译的可执行文件版本】

  • 标准PE32(+)二进制
    • x86
    • x64
    • ARM64 Native
    • ARM Thumb-2
  • 混合/变色龙PE32(+)二进制
    • CHPE:x86二进制(包含ARM64和x86机器码)(需要EWDK编译)
    • ARM64EC:x64二进制(包含ARM64和x64机器码)
    • ARM64X:ARM64 Native二进制(包含ARM64EC(x64兼容)变色龙模式)

【程序需要编译为什么版本】

一般的程序,一般建议编译x86、x64、ARM64 Native版本:

  • x86 -> x86、x64、ARM64系统
  • x64 -> x64、ARM64(Win11+)系统
  • ARM64 Native -> ARM64系统
    • 如果对与x64共享二进制组件有需求,或无法编译为ARM64 Native,而且仅需要优化性能,可以考虑ARM64EC

安装到System32的,或注册为COM/ActiveX组件的,或注册为注入其它进程的DLL,一般需要编译x86、x64、ARM64X版本:

  • 在x86系统:x86 -> System32
  • 在x64系统:x64 -> System32,x86 -> SysWOW64
  • 在ARM64系统:ARM64X -> System32,x86 -> SysWOW64

如果不能编译为ARM64X版本,可以使用最新版本MSVC的Visual C++ ARM64生成工具生成一个ARM64X纯转发DLL,具体方法见下文

驱动程序(包含UMDF和打印机驱动)一般需要编译x86、x64、ARM64 Native版本,在对应的系统使用对应的版本

EXE编译为ARM64X有特殊效果:ARM64 Native程序运行它,系统会运行它内部的ARM64 Native版本,x64/ARM64EC程序运行它,系统会运行它内部的ARM64EC版本,Win11 22H2支持使用start /machine arm64和start /machine amd64指定运行哪一版本(Win11 21H2只能使用当前未文档化的WinAPI)

【如何判断系统是不是Win11 ARM64】

判断系统是不是Win11 ARM64可分为两步:判断系统是不是Win11和判断系统是不是ARM64

判断系统是不是Win11有很多种方法;Win11最早的版本是10.0.22000,可以用ntdll.dll的RtlGetVersionRtlVerifyVersionInfo判断,它们是GetVersionEx或VerifyVersionInfo的替代品,区别只是返回值改成了NTSTATUS,可使用NT_SUCCESS(x)转换为BOOL,不建议使用后两者,它们被弃用(deprecated)了,而且它的行为依赖于manifest的设置;也可以判断kernel32.dll有没有GetMachineTypeAttributes这个API;虽然有风险,但是事实上也可以使用ntdll.dll的RtlNtGetVersionNumbers这个未文档化的API

判断系统是不是ARM64不能使用kernel32.dll中的GetNativeSystemInfo(原因见本文最后的测试结果)或RuntimeInformation.OSArchitecture,可以使用kernel32.dll中的IsWow64Process2

WINBASEAPIBOOLWINAPIIsWow64Process2(    _In_ HANDLE hProcess,    _Out_ USHORT* pProcessMachine,    _Out_opt_ USHORT* pNativeMachine    );

返回TRUE表示成功,第一个参数可以是GetCurrentProcess(),也可以是有PROCESS_QUERY_INFORMATION或PROCESS_QUERY_LIMITED_INFORMATION权限的进程句柄,第二个参数如果是64位进程会返回IMAGE_FILE_MACHINE_UNKNOWN(0),如果是32位进程则返回进程的体系结构;第三个参数返回系统的原生体系结构,常见体系结构值如下:

  • IMAGE_FILE_MACHINE_I386(0x14C)【x86,32位】
  • IMAGE_FILE_MACHINE_AMD64(0x8664)【x64,64位】
  • IMAGE_FILE_MACHINE_ARMNT(0x1C4)【ARM,32位】
  • IMAGE_FILE_MACHINE_ARM64(0xAA64)【ARM64,64位】

如果需要兼容老系统,C/C++中可以使用GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process2")获取WinAPI入口点,.NET中可以通过处理EntryPointNotFoundException实现

【Visual C++运行时和.NET运行时】

Visual C++最新版运行时将ARM64运行时升级为ARM64X运行时,以同时兼容x64/ARM64EC和ARM64 Native程序:

  • VS15.9和VC14.16是第一个包含ARM64运行时的VS的VC版本
  • VS16.11和VC14.29是第一个包含ARM64X运行时的VS的VC版本(x64安装程序包含x64和ARM64X的DLL)
  • EWDK22000包含VC14.28,运行时DLL升级为ARM64X,但x64安装程序没有更新
  • Win11 ARM64在C:\Windows\apppatch\VCRedistARM64XConflictPrevention\VC_redist.arm64.exe放置了一个ARM64X运行时的安装程序,用于替代老版本的x64/ARM64运行时安装程序以避免安装冲突,这个功能是21318引入的,这个机制有一定的缺陷,因此不建议依赖老版本的运行时

.NET Framework在Win10 1903以后已经停留在版本4.8停止更新,在Win10 ARM64只有x86版本,在Win11 21H2 ARM64只有x86和x64版本,在Win11 22H2更新为版本4.8.1,Win11 22H2 ARM64增加ARM64 Native版本。

.NET (Core)在Win11 ARM64系统上共存的方式为arm64(ARM64 Native)版本安装到%programfiles%\dotnet,x64版本安装到%programfiles%\dotnet\x64,默认运行arm64版本,使用dotnet -a x64运行x64版本,为了避免安装路径冲突,建议安装如下版本的新版x64/arm64运行时或SDK,不要安装老版本:

  • 3.1.21(x64)运行时、3.1.415(x64)SDK
  • 5.0.12(x64/arm64)运行时、5.0.403(x64/arm64)SDK(已停止支持)
  • 6.0.0(x64/arm64)运行时和SDK

.NET Support for macOS 11 and Windows 11 for Arm64 and x64 · Issue #22380 · dotnet/sdk (github.com)

【ARM64EC格式和ARM64X格式的技术细节】

ARM64EC:包含ARM64指令的x64可执行文件

  • 表现为x64程序,但可以混合x64和ARM64指令的模块
  • 默认链接的静态库是ARM64指令的,因此不能在x64系统运行
  • 不能在Win10 ARM64运行,只能在Win11 ARM64运行
  • 二进制特征:
    • 机器类型为x64程序(0x8664)
    • 包含.a64xrm和.hexpthk两个节
    • IMAGE_DATA_DIRECTORY_LOAD_CONFIG包含非空的CHPEMetadataPointer(ULONGLONG偏移200,虚拟地址)字段
  • 加入的编译器开关:/arm64EC /D _AMD64_ /D AMD64 /D _ARM64EC_ /D ARM64EC
  • 加入的链接器开关:/machine:arm64ec softintrin.lib

ARM64X:在原生ARM64可执行文件的基础上复合了ARM64EC版本的可执行文件

  • 默认在原生ARM64模式执行,但被x64程序调用时会变为ARM64EC可执行文件,执行复合进去的ARM64EC版本
  • 大多数用户态系统文件编译为这种格式
  • 在Win10 ARM64下面可以被识别为原生ARM64可执行文件,因此兼容Win10 ARM64
  • ARM64EC项目属性高级可设置编译为ARM64X
  • 二进制特征:
    • 机器类型为ARM64程序(0xaa64)
    • 包含.a64xrm和.hexpthk两个节
    • IMAGE_DATA_DIRECTORY_LOAD_CONFIG包含非空的CHPEMetadataPointer(ULONGLONG偏移200,虚拟地址)、DynamicValueRelocTableOffset(ULONG偏移224)和DynamicValueRelocTableSection字段(USHORT偏移228)
  • 加入的链接器开关:/machine:arm64x softintrin.lib
  • 可选链接器开关:
    • /def: /defarm64native: 对ARM64EC和ARM64版本指定不同def文件

关于ARM64EC,可以参考:

Arm64EC for Windows 11 apps on Arm | Microsoft Docs

Get started with Arm64EC apps for Windows 11 on Arm | Microsoft Docs

Understanding Arm64EC ABI and assembly code | Microsoft Docs

Overview of ARM64EC ABI conventions | Microsoft Docs

关于ARM64X,可以参考: 

Arm64X PE Files | Microsoft Docs

Build Arm64X Files | Microsoft Docs

【生成ARM64X纯转发DLL】

在Win11 ARM64中,x64/ARM64EC和ARM64程序均想使用同一个全局DLL名称foo.dll,但是你只有单独的x64版本(或ARM64EC版本)以及ARM64版本,但是并没有ARM64X版本,为了支持Win11 ARM64,你需要将x64版本(或ARM64EC版本)重命名为foo_x64.dll,ARM64版本重命名为foo_arm64.dll,然后使用下面的方法生成适用于Win11 ARM64的foo.dll

1、确保安装了Visual C++ ARM64生成工具

2、编写foo_x64.def

EXPORTS    MyAPI1  =  foo_x64.MyAPI1    MyAPI2  =  foo_x64.MyAPI2

3、编写foo_arm64.def

EXPORTS    MyAPI1  =  foo_arm64.MyAPI1    MyAPI2  =  foo_arm64.MyAPI2

4、准备一个空白的empty.cpp

5、使用下面的命令构建ARM64X纯转发DLL

:: 使用真实安装路径替代下面的路径"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"cl /c /Foempty_arm64.obj empty.cppcl /c /arm64EC /Foempty_x64.obj empty.cpplink /lib /machine:x64 /def:foo_x64.def /out:foo_x64.liblink /lib /machine:arm64 /def:foo_arm64.def /out:foo_arm64.liblink /dll /noentry /machine:arm64x /defArm64Native:foo_arm64.def /def:foo_x64.def empty_arm64.obj empty_x64.obj /out:foo.dll foo_arm64.lib foo_x64.lib

【关于ARM32 WOW64支持】

Windows 10/11 ARM64的ARM32支持主要用于以下应用程序:

  • UWP Apps ARM32版(早期主要用于Win10Mobile[1507,1511-1703,1709(15254)]、Win10IoTCore[1507-1607,1703-1809])
  • Win32应用程序ARM32版(早期主要用于Win10IoTCore[1703-1809]、NanoServer[1709-1809])

不支持以下应用程序:

  • Windows RT、RT 8.1 Apps
  • Office 2013 RT
  • Windows Phone Silverlight Apps
  • Windows Phone 8.1 Windows Runtime Apps

现在ARM32支持已经被ARM废弃,Apple Sillicon M1和ARMv9-A中的Cortex-X2和Cortex-A510已不支持运行ARM32程序(Cortex-A710仍然支持),以后很可能大多数ARM64处理器都不再支持运行ARM32程序,再加上可以运行第三方Win32程序的ARM32版本Windows只有少数几个小众的版本,并且均已停止开发,因此对于大多数开发者来说,已经没必要编译ARM32版本的Win32程序了

Win11 21H2和之前的系统始终使用CPU的AArch32模式运行ARM32应用程序,在Apple Sillicon M1和ARMv9-A中的Cortex-X2和Cortex-A510等不支持AArch32模式的新处理器中ARM32应用程序会闪退,Win11 22H2和以后的系统会报不支持该应用程序而不是闪退

【x86/x64/ARM64等多体系结构支持有关的WinAPI】

早期API:GetSystemInfo

传统API(WinXP、Win2003):

  • GetNativeSystemInfo
  • IsWow64Process
  • GetSystemWow64Directory(Win2003)
  • Wow64DisableWow64FsRedirection(Win2003)
  • Wow64RevertWow64FsRedirection(Win2003)

Win10新API(Win10 1709 Build 16299):

  • IsWow64Process2
  • IsWow64GuestMachineSupported
  • GetSystemWow64Directory2(kernelbase.dll)
  • Wow64SetThreadDefaultGuestMachine(kernelbase.dll,当前docs没有,但是出现在头文件)

Win11新API(Win11):

  • GetMachineTypeAttributes
  • GetProcessInformation
    • ProcessMachineTypeInfo
    • PROCESS_MACHINE_INFORMATION
  • CreateProcess
    • InitializeProcThreadAttributeList
    • UpdateProcThreadAttributes
      • PROC_THREAD_ATTRIBUTE_MACHINE_TYPE(当前docs没有,但是出现在头文件)
    • DeleteProcThreadAttributeList

【各种WinAPI在Win10/11 ARM64不同类型进程下的返回值测试结果】

Windows 10 Version 1903(1909)/2004(20H2/21H1/21H2) ARM64测试结果:

  • ARM应用返回值:
    • GetSystemInfo:5(ARM)
    • GetNativeSystemInfo:12(ARM64)
    • IsWow64Process:0
    • IsWow64Process2:0x01c4(ARMNT)、0xaa64(ARM64)
    • GetProcessInformation:0x0000、0
    • GetSystemWow64DirectoryA=C:\windows\SysArm32
  • ARM64应用返回值:
    • GetSystemInfo:12(ARM64)
    • GetNativeSystemInfo:12(ARM64)
    • IsWow64Process:0
    • IsWow64Process2:0x0000(UNKNOWN)、0xaa64(ARM64)
    • GetProcessInformation:0x0000、0
    • GetSystemWow64DirectoryA=C:\windows\SysWOW64
  • x86应用返回值:
    • GetSystemInfo:0(INTEL)
    • GetNativeSystemInfo:0(INTEL)
    • IsWow64Process:0
    • IsWow64Process2:0x014c(I386)、0xaa64(ARM64)
    • GetProcessInformation:0x0000、0
    • GetSystemWow64DirectoryA=C:\windows\SysWOW64
  • 通用返回值:
    • IsWow64GuestMachineSupported:0x014c(I386)、0x01c4(ARMNT)
    • GetSystemWow64Directory2A:
      • 0x0001(TARGET_HOST):C:\windows\system32
      • 0x014c(I386):C:\windows\SysWOW64
      • 0x01c4(ARMNT):C:\windows\SysArm32
      • 0x8664(AMD64):C:\windows\SysX8664
      • 0xaa64(ARM64):C:\windows\SysArm64

Windows 11 ARM64测试结果:

  • ARM应用返回值:
    • GetSystemInfo:5(ARM)
    • GetNativeSystemInfo:12(ARM64)
    • IsWow64Process:1
    • IsWow64Process2:0x01c4(ARMNT)、0xaa64(ARM64)
    • GetProcessInformation:0x01c4(ARMNT)、5(UserEnabled+Wow64Container)
    • GetSystemWow64DirectoryA=C:\windows\SysArm32
  • ARM64应用返回值:
    • GetSystemInfo:12(ARM64)
    • GetNativeSystemInfo:12(ARM64)
    • IsWow64Process:0
    • IsWow64Process2:0x0000(UNKNOWN)、0xaa64(ARM64)
    • GetProcessInformation:0xaa64(ARM64)、3(UserEnabled+KernelEnabled)
    • GetSystemWow64DirectoryA=C:\windows\SysWOW64
  • x64/ARM64EC应用返回值:
    • GetSystemInfo:9(AMD64)
    • GetNativeSystemInfo:9(AMD64)
    • IsWow64Process:0
    • IsWow64Process2:0x0000(UNKNOWN)、0xaa64(ARM64)
    • GetProcessInformation:0x8664(AMD64)、1(UserEnabled)
    • GetSystemWow64DirectoryA=C:\windows\SysWOW64
  • x86应用返回值:
    • GetSystemInfo:0(INTEL)
    • GetNativeSystemInfo:9(AMD64)
    • IsWow64Process:1
    • 兼容性设置隐藏x64支持后:
      • ​​​​GetNativeSystemInfo:0(INTEL)
      • IsWow64Process:0
    • IsWow64Process2:0x014c(I386)、0xaa64(ARM64)
    • GetProcessInformation:0x014c(I386)、5(UserEnabled+Wow64Container)
    • GetSystemWow64DirectoryA=C:\windows\SysWOW64
  • 通用返回值:
    • IsWow64GuestMachineSupported:0x014c(I386)、0x01c4(ARMNT)
    • GetSystemWow64Directory2A:
      • 0x0001(TARGET_HOST):C:\windows\system32
      • 0x014c(I386):C:\windows\SysWOW64
      • 0x01c4(ARMNT):C:\windows\SysArm32
    • GetMachineTypeAttributes:见上文GetProcessInformation