From fccc04d3e72bb462cba1b492ba0e2cd4ab2aebec Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 16 Jul 2018 16:38:56 -0700 Subject: [PATCH] Start adding an `aarch64-pc-windows-msvc` target This commit adds the necessary definitions for target specs and such as well as the necessary support in libstd to compile basic `aarch64-pc-windows-msvc` binaries. The target is not currently built on CI, but it can be built locally with: ./configure --target=aarch64-pc-windows-msvc --set rust.lld ./x.py build src/libstd --target aarch64-pc-windows-msvc Currently this fails to build `libtest` due to a linker bug (seemingly in LLD?) which hasn't been investigate yet. Otherwise though with libstd you can build a hello world program (linked with LLD). I've not tried to execute it yet, but it at least links! Full support for this target is still a long road ahead, but this is hopefully a good stepping stone to get started. Points of note about this target are: * Currently defaults to `panic=abort` as support is still landing in LLVM for SEH on AArch64. * Currently defaults to LLD as a linker as I was able to get farther with it than I was with `link.exe` --- src/libpanic_unwind/{wasm32.rs => dummy.rs} | 0 src/libpanic_unwind/lib.rs | 55 ++++++++-------- src/libpanic_unwind/macros.rs | 45 +++++++++++++ .../spec/aarch64_pc_windows_msvc.rs | 35 ++++++++++ src/librustc_target/spec/mod.rs | 1 + src/libstd/sys/windows/backtrace/mod.rs | 24 +++++++ src/libstd/sys/windows/c.rs | 64 ++++++++++++++++++- src/libstd/sys/windows/mod.rs | 10 ++- 8 files changed, 201 insertions(+), 33 deletions(-) rename src/libpanic_unwind/{wasm32.rs => dummy.rs} (100%) create mode 100644 src/libpanic_unwind/macros.rs create mode 100644 src/librustc_target/spec/aarch64_pc_windows_msvc.rs diff --git a/src/libpanic_unwind/wasm32.rs b/src/libpanic_unwind/dummy.rs similarity index 100% rename from src/libpanic_unwind/wasm32.rs rename to src/libpanic_unwind/dummy.rs diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index a61b2c1f06394..9c3fc76c307a6 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -55,36 +55,33 @@ use core::mem; use core::raw; use core::panic::BoxMeUp; -// Rust runtime's startup objects depend on these symbols, so make them public. -#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] -pub use imp::eh_frame_registry::*; +#[macro_use] +mod macros; -// *-pc-windows-msvc -#[cfg(target_env = "msvc")] -#[path = "seh.rs"] -mod imp; - -// x86_64-pc-windows-gnu -#[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] -#[path = "seh64_gnu.rs"] -mod imp; - -// i686-pc-windows-gnu and all others -#[cfg(any(all(unix, not(target_os = "emscripten")), - target_os = "cloudabi", - target_os = "redox", - all(windows, target_arch = "x86", target_env = "gnu")))] -#[path = "gcc.rs"] -mod imp; - -// emscripten -#[cfg(target_os = "emscripten")] -#[path = "emcc.rs"] -mod imp; - -#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] -#[path = "wasm32.rs"] -mod imp; +cfg_if! { + if #[cfg(target_os = "emscripten")] { + #[path = "emcc.rs"] + mod imp; + } else if #[cfg(target_arch = "wasm32")] { + #[path = "dummy.rs"] + mod imp; + } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { + #[path = "dummy.rs"] + mod imp; + } else if #[cfg(target_env = "msvc")] { + #[path = "seh.rs"] + mod imp; + } else if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] { + #[path = "seh64_gnu.rs"] + mod imp; + } else { + // Rust runtime's startup objects depend on these symbols, so make them public. + #[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))] + pub use imp::eh_frame_registry::*; + #[path = "gcc.rs"] + mod imp; + } +} mod dwarf; mod windows; diff --git a/src/libpanic_unwind/macros.rs b/src/libpanic_unwind/macros.rs new file mode 100644 index 0000000000000..6ea79dc862bda --- /dev/null +++ b/src/libpanic_unwind/macros.rs @@ -0,0 +1,45 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A macro for defining `#[cfg]` if-else statements. +/// +/// This is similar to the `if/elif` C preprocessor macro by allowing definition +/// of a cascade of `#[cfg]` cases, emitting the implementation which matches +/// first. +/// +/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code +/// without having to rewrite each clause multiple times. +macro_rules! cfg_if { + ($( + if #[cfg($($meta:meta),*)] { $($it:item)* } + ) else * else { + $($it2:item)* + }) => { + __cfg_if_items! { + () ; + $( ( ($($meta),*) ($($it)*) ), )* + ( () ($($it2)*) ), + } + } +} + +macro_rules! __cfg_if_items { + (($($not:meta,)*) ; ) => {}; + (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { + __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } + __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } + } +} + +macro_rules! __cfg_if_apply { + ($m:meta, $($it:item)*) => { + $(#[$m] $it)* + } +} diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs new file mode 100644 index 0000000000000..8747f239d3418 --- /dev/null +++ b/src/librustc_target/spec/aarch64_pc_windows_msvc.rs @@ -0,0 +1,35 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use spec::{LinkerFlavor, Target, TargetResult, PanicStrategy, LldFlavor}; + +pub fn target() -> TargetResult { + let mut base = super::windows_msvc_base::opts(); + base.max_atomic_width = Some(64); + base.has_elf_tls = true; + + // FIXME: this shouldn't be panic=abort, it should be panic=unwind + base.panic_strategy = PanicStrategy::Abort; + base.linker = Some("rust-lld".to_owned()); + + Ok(Target { + llvm_target: "aarch64-pc-windows-msvc".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "64".to_string(), + target_c_int_width: "32".to_string(), + data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(), + arch: "aarch64".to_string(), + target_os: "windows".to_string(), + target_env: "msvc".to_string(), + target_vendor: "pc".to_string(), + linker_flavor: LinkerFlavor::Lld(LldFlavor::Link), + options: base, + }) +} diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index d55762e03eee3..3a18c56f4fc59 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -355,6 +355,7 @@ supported_targets! { ("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu), ("i686-pc-windows-gnu", i686_pc_windows_gnu), + ("aarch64-pc-windows-msvc", aarch64_pc_windows_msvc), ("x86_64-pc-windows-msvc", x86_64_pc_windows_msvc), ("i686-pc-windows-msvc", i686_pc_windows_msvc), ("i586-pc-windows-msvc", i586_pc_windows_msvc), diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 7ef4e203571b2..f64cae810b9ac 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -229,6 +229,7 @@ impl StackFrame for c::STACKFRAME_EX { self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; c::IMAGE_FILE_MACHINE_I386 } + #[cfg(target_arch = "x86_64")] fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { self.AddrPC.Offset = ctx.Rip as u64; @@ -240,6 +241,17 @@ impl StackFrame for c::STACKFRAME_EX { c::IMAGE_FILE_MACHINE_AMD64 } + #[cfg(target_arch = "aarch64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Pc as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Sp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Fp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_ARM64 + } + fn get_addr(&self) -> *const u8 { (self.AddrPC.Offset - 1) as *const u8 } @@ -260,6 +272,7 @@ impl StackFrame for c::STACKFRAME64 { self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; c::IMAGE_FILE_MACHINE_I386 } + #[cfg(target_arch = "x86_64")] fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { self.AddrPC.Offset = ctx.Rip as u64; @@ -271,6 +284,17 @@ impl StackFrame for c::STACKFRAME64 { c::IMAGE_FILE_MACHINE_AMD64 } + #[cfg(target_arch = "aarch64")] + fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD { + self.AddrPC.Offset = ctx.Pc as u64; + self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrStack.Offset = ctx.Sp as u64; + self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat; + self.AddrFrame.Offset = ctx.Fp as u64; + self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat; + c::IMAGE_FILE_MACHINE_ARM64 + } + fn get_addr(&self) -> *const u8 { (self.AddrPC.Offset - 1) as *const u8 } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 6f81afe66f95b..e514a56dcc436 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -280,6 +280,9 @@ pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; #[cfg(target_arch = "x86_64")] #[cfg(feature = "backtrace")] pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; +#[cfg(target_arch = "aarch64")] +#[cfg(feature = "backtrace")] +pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64; pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; @@ -791,9 +794,68 @@ pub struct FLOATING_SAVE_AREA { // will not appear in the final documentation. This should be also defined for // other architectures supported by Windows such as ARM, and for historical // interest, maybe MIPS and PowerPC as well. -#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))] +#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))] pub enum CONTEXT {} +#[cfg(target_arch = "aarch64")] +pub const ARM64_MAX_BREAKPOINTS: usize = 8; + +#[cfg(target_arch = "aarch64")] +pub const ARM64_MAX_WATCHPOINTS: usize = 2; + +#[cfg(target_arch = "aarch64")] +#[repr(C)] +pub struct ARM64_NT_NEON128 { + pub D: [f64; 2], +} + +#[cfg(target_arch = "aarch64")] +#[repr(C, align(16))] +pub struct CONTEXT { + pub ContextFlags: DWORD, + pub Cpsr: DWORD, + pub X0: u64, + pub X1: u64, + pub X2: u64, + pub X3: u64, + pub X4: u64, + pub X5: u64, + pub X6: u64, + pub X7: u64, + pub X8: u64, + pub X9: u64, + pub X10: u64, + pub X11: u64, + pub X12: u64, + pub X13: u64, + pub X14: u64, + pub X15: u64, + pub X16: u64, + pub X17: u64, + pub X18: u64, + pub X19: u64, + pub X20: u64, + pub X21: u64, + pub X22: u64, + pub X23: u64, + pub X24: u64, + pub X25: u64, + pub X26: u64, + pub X27: u64, + pub X28: u64, + pub Fp: u64, + pub Lr: u64, + pub Sp: u64, + pub Pc: u64, + pub V: [ARM64_NT_NEON128; 32], + pub Fpcr: DWORD, + pub Fpsr: DWORD, + pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS], + pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS], + pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS], +} + #[repr(C)] pub struct SOCKADDR_STORAGE_LH { pub ss_family: ADDRESS_FAMILY, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 0d12ecf8fe3a1..ccf79de909fa9 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { // handlers. // // https://msdn.microsoft.com/en-us/library/dn774154.aspx -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(unreachable_code)] pub unsafe fn abort_internal() -> ! { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + ::intrinsics::unreachable(); + } + ::intrinsics::abort(); }