Skip to content

Commit fdb14ac

Browse files
committed
Add support for Arm64EC to the Standard Library
1 parent d5db7fb commit fdb14ac

File tree

6 files changed

+58
-36
lines changed

6 files changed

+58
-36
lines changed

library/core/src/hint.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ pub fn spin_loop() {
237237
crate::arch::riscv64::pause();
238238
}
239239

240-
#[cfg(target_arch = "aarch64")]
240+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec"))]
241241
{
242242
// SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
243243
unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };

library/panic_abort/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pub unsafe fn __rust_start_panic(_payload: &mut dyn PanicPayload) -> u32 {
8181
} else if #[cfg(target_arch = "aarch64")] {
8282
core::arch::asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
8383
} else {
84+
// This is currently used for ARM64EC since we don't support inline assembly.
8485
core::intrinsics::abort();
8586
}
8687
}

library/std/src/sys/pal/common/alloc.rs

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub const MIN_ALIGN: usize = 8;
2323
#[cfg(any(
2424
target_arch = "x86_64",
2525
target_arch = "aarch64",
26+
target_arch = "arm64ec",
2627
target_arch = "loongarch64",
2728
target_arch = "mips64",
2829
target_arch = "mips64r6",

library/std/src/sys/pal/windows/c/windows_sys.rs

+18-18
Original file line numberDiff line numberDiff line change
@@ -1018,7 +1018,7 @@ impl Clone for CONTEXT_0_0 {
10181018
}
10191019
}
10201020
#[repr(C)]
1021-
#[cfg(target_arch = "x86_64")]
1021+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10221022
pub struct CONTEXT {
10231023
pub P1Home: u64,
10241024
pub P2Home: u64,
@@ -1067,30 +1067,30 @@ pub struct CONTEXT {
10671067
pub LastExceptionToRip: u64,
10681068
pub LastExceptionFromRip: u64,
10691069
}
1070-
#[cfg(target_arch = "x86_64")]
1070+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10711071
impl Copy for CONTEXT {}
1072-
#[cfg(target_arch = "x86_64")]
1072+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10731073
impl Clone for CONTEXT {
10741074
fn clone(&self) -> Self {
10751075
*self
10761076
}
10771077
}
10781078
#[repr(C)]
1079-
#[cfg(target_arch = "x86_64")]
1079+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10801080
pub union CONTEXT_0 {
10811081
pub FltSave: XSAVE_FORMAT,
10821082
pub Anonymous: CONTEXT_0_0,
10831083
}
1084-
#[cfg(target_arch = "x86_64")]
1084+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10851085
impl Copy for CONTEXT_0 {}
1086-
#[cfg(target_arch = "x86_64")]
1086+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10871087
impl Clone for CONTEXT_0 {
10881088
fn clone(&self) -> Self {
10891089
*self
10901090
}
10911091
}
10921092
#[repr(C)]
1093-
#[cfg(target_arch = "x86_64")]
1093+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
10941094
pub struct CONTEXT_0_0 {
10951095
pub Header: [M128A; 2],
10961096
pub Legacy: [M128A; 8],
@@ -1111,9 +1111,9 @@ pub struct CONTEXT_0_0 {
11111111
pub Xmm14: M128A,
11121112
pub Xmm15: M128A,
11131113
}
1114-
#[cfg(target_arch = "x86_64")]
1114+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
11151115
impl Copy for CONTEXT_0_0 {}
1116-
#[cfg(target_arch = "x86_64")]
1116+
#[cfg(any(target_arch = "x86_64", target_arch = "arm64ec"))]
11171117
impl Clone for CONTEXT_0_0 {
11181118
fn clone(&self) -> Self {
11191119
*self
@@ -3339,7 +3339,7 @@ pub const FILE_WRITE_EA: FILE_ACCESS_RIGHTS = 16u32;
33393339
pub const FILE_WRITE_THROUGH: NTCREATEFILE_CREATE_OPTIONS = 2u32;
33403340
pub const FIONBIO: i32 = -2147195266i32;
33413341
#[repr(C)]
3342-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
3342+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
33433343
pub struct FLOATING_SAVE_AREA {
33443344
pub ControlWord: u32,
33453345
pub StatusWord: u32,
@@ -3351,9 +3351,9 @@ pub struct FLOATING_SAVE_AREA {
33513351
pub RegisterArea: [u8; 80],
33523352
pub Cr0NpxState: u32,
33533353
}
3354-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
3354+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
33553355
impl Copy for FLOATING_SAVE_AREA {}
3356-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
3356+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
33573357
impl Clone for FLOATING_SAVE_AREA {
33583358
fn clone(&self) -> Self {
33593359
*self
@@ -4106,7 +4106,7 @@ impl Clone for WSABUF {
41064106
}
41074107
}
41084108
#[repr(C)]
4109-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4109+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
41104110
pub struct WSADATA {
41114111
pub wVersion: u16,
41124112
pub wHighVersion: u16,
@@ -4116,9 +4116,9 @@ pub struct WSADATA {
41164116
pub szDescription: [i8; 257],
41174117
pub szSystemStatus: [i8; 129],
41184118
}
4119-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4119+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
41204120
impl Copy for WSADATA {}
4121-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4121+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
41224122
impl Clone for WSADATA {
41234123
fn clone(&self) -> Self {
41244124
*self
@@ -4286,7 +4286,7 @@ pub const WSA_SECURE_HOST_NOT_FOUND: WSA_ERROR = 11032i32;
42864286
pub const WSA_WAIT_EVENT_0: WSA_ERROR = 0i32;
42874287
pub const WSA_WAIT_IO_COMPLETION: WSA_ERROR = 192i32;
42884288
#[repr(C)]
4289-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4289+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
42904290
pub struct XSAVE_FORMAT {
42914291
pub ControlWord: u16,
42924292
pub StatusWord: u16,
@@ -4305,9 +4305,9 @@ pub struct XSAVE_FORMAT {
43054305
pub XmmRegisters: [M128A; 16],
43064306
pub Reserved4: [u8; 96],
43074307
}
4308-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4308+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
43094309
impl Copy for XSAVE_FORMAT {}
4310-
#[cfg(any(target_arch = "aarch64", target_arch = "x86_64"))]
4310+
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
43114311
impl Clone for XSAVE_FORMAT {
43124312
fn clone(&self) -> Self {
43134313
*self

library/std/src/sys/pal/windows/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
325325
/// that function for more information on `__fastfail`
326326
#[cfg(not(miri))] // inline assembly does not work in Miri
327327
pub fn abort_internal() -> ! {
328+
#[allow(unused_unsafe)]
328329
unsafe {
329330
cfg_if::cfg_if! {
330331
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
@@ -334,6 +335,7 @@ pub fn abort_internal() -> ! {
334335
} else if #[cfg(target_arch = "aarch64")] {
335336
core::arch::asm!("brk 0xF003", in("x0") c::FAST_FAIL_FATAL_APP_EXIT, options(noreturn, nostack));
336337
} else {
338+
// This is currently used for ARM64EC since we don't support inline assembly.
337339
core::intrinsics::abort();
338340
}
339341
}

src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md

+35-17
Original file line numberDiff line numberDiff line change
@@ -11,48 +11,66 @@ applications on AArch64 Windows 11. See <https://learn.microsoft.com/en-us/windo
1111

1212
## Requirements
1313

14-
Target only supports cross-compilation, `core` and `alloc` are supported but
15-
`std` is not.
16-
1714
Builds Arm64EC static and dynamic libraries and executables which can be run on
1815
AArch64 Windows 11 devices. Arm64EC static libraries can also be linked into
1916
Arm64X dynamic libraries and executables.
2017

21-
Uses `arm64ec` as its `target_arch` - code built for Arm64EC must be compatible
22-
with x86_64 code (e.g., same structure layouts, function signatures, etc.) but
23-
use AArch64 intrinsics.
24-
25-
Only supported backend is LLVM 18 (or above).
18+
Only supported backend is LLVM 18.1.0 or above (18.1.2 or above is required for
19+
`raw-dylib` support).
20+
21+
### Reusing code from other architectures - x86_64 or AArch64?
22+
23+
Arm64EC uses `arm64ec` as its `target_arch`, but it is possible to reuse
24+
existing architecture-specific code in most cases. The best mental model for
25+
deciding which architecture to reuse is to is to think of Arm64EC as an x86_64
26+
process that happens to use the AArch64 instruction set (with some caveats) and
27+
has a completely custom ABI.
28+
29+
To put this in practice:
30+
* Arm64EC interacts with the operating system, other processes and other DLLs as
31+
x86_64.
32+
- For example, [in `backtrace`](https://github.com/rust-lang/backtrace-rs/commit/ef39a7d7da58b4cae8c8f3fc67a8300fd8d2d0d9)
33+
we use the x86_64 versions of `CONTEXT` and `RtlVirtualUnwind`.
34+
- If you are configuring a search path to find DLLs (e.g., to load plugins or
35+
addons into your application), you should use the same path as the x86_64
36+
version of your application, not the AArch64 path (since Arm64EC (i.e.,
37+
x86_64) processes cannot load native AArch64 DLLs).
38+
* Arm64EC uses AArch64 intrinsics.
39+
- For example, <https://github.com/rust-lang/portable-simd/commit/ca4033f49b1f6019561b8b161b4097b4a07f2e1b>
40+
and <https://github.com/rust-lang/stdarch/commit/166ef7ba22b6a1d908d4b29a36e68ceca324808a>.
41+
* Assembly for AArch64 might be reusable for Arm64EC, but there are many
42+
caveats. For full details see [Microsoft's documentation on the Arm64EC ABI](https://learn.microsoft.com/en-us/windows/arm/arm64ec-abi)
43+
but in brief:
44+
- Arm64EC uses a restricted set of AArch64 registers.
45+
- Arm64EC uses a different name mangling scheme than AArch64.
46+
- Arm64EC requires entry and exit thunks be generated for some functions.
47+
- Indirect calls must be done via a call checker.
48+
- Control Flow Guard and stack checks use different functions than AArch64.
2649

2750
## Building the target
2851

2952
You can build Rust with support for the targets by adding it to the `target`
30-
list in `config.toml` and disabling `std`:
53+
list in `config.toml`:
3154

3255
```toml
3356
[build]
3457
target = [ "arm64ec-pc-windows-msvc" ]
35-
36-
[target.arm64ec-pc-windows-msvc]
37-
no-std = true
3858
```
3959

4060
## Building Rust programs
4161

4262
Rust does not yet ship pre-compiled artifacts for this target. To compile for
4363
this target, you will either need to build Rust with the target enabled (see
44-
"Building the target" above), or build your own copy of `core` by using
45-
`build-std` or similar.
64+
"Building the target" above), or build your own copy using `build-std` or
65+
similar.
4666

4767
## Testing
4868

4969
Tests can be run on AArch64 Windows 11 devices.
5070

51-
Since this is a `no_std` target, the Rust test suite is not supported.
52-
5371
## Cross-compilation toolchains and C code
5472

55-
C code can be built using the Arm64-targetting MSVC toolchain.
73+
C code can be built using the Arm64-targetting MSVC or Clang toolchain.
5674

5775
To compile:
5876

0 commit comments

Comments
 (0)