Skip to content

Commit

Permalink
Enable building and running on Windows ARM64
Browse files Browse the repository at this point in the history
I agree to license my contributions to each file under the terms given at the top of each file I changed.

Co-authored-by: Marc-André Moreau <marcandre.moreau@gmail.com>
  • Loading branch information
Alovchin91 and awakecoding committed Aug 16, 2021
1 parent 8fe3633 commit e8e9a67
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 51 deletions.
15 changes: 15 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ jobs:
toolchain: stable
profile: minimal

- run: echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH
shell: bash

- run: sh mk/package.sh
shell: bash

Expand All @@ -167,6 +170,7 @@ jobs:
- aarch64-apple-ios
- aarch64-apple-darwin
- aarch64-linux-android
- aarch64-pc-windows-msvc
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- arm-unknown-linux-gnueabihf
Expand Down Expand Up @@ -234,6 +238,11 @@ jobs:
# TODO: https://github.com/briansmith/ring/issues/486
cargo_options: --no-run

- target: aarch64-pc-windows-msvc
host_os: windows-latest
# GitHub Actions doesn't have a way to run this target yet.
cargo_options: --no-run

- target: aarch64-unknown-linux-gnu
host_os: ubuntu-18.04

Expand Down Expand Up @@ -303,6 +312,12 @@ jobs:
sudo xcode-select -s /Applications/Xcode_12.4.app &&
sudo rm -Rf /Library/Developer/CommandLineTools/SDKs/*
- if: ${{ matrix.target == 'aarch64-pc-windows-msvc' }}
run: |
echo "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin" >> $GITHUB_PATH
echo "RUSTFLAGS=-C target-feature=+crt-static" >> $GITHUB_ENV
shell: bash

- if: ${{ !contains(matrix.host_os, 'windows') }}
run: |
mk/cargo.sh test -vv --all-targets --target=${{ matrix.target }} ${{ matrix.cargo_options }} ${{ matrix.features }} ${{ matrix.mode }}
Expand Down
47 changes: 40 additions & 7 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,12 @@ apply when building from crates.io:
primitives (32- and 64- bit Intel, and 32- and 64-bit ARM), Perl must be
installed and in `$PATH`.

* For Windows targets, `target/tools/windows/nasm/nasm[.exe]` is used as the
assembler. The version to use and how to download it is documented in
[.github/workflows/ci.yml](.github/workflows/ci.yml).
* For Windows targets except ARM64, `target/tools/windows/nasm/nasm[.exe]`
is used as the assembler. The version to use and how to download it is
documented in [.github/workflows/ci.yml](.github/workflows/ci.yml).

* For Windows ARM64 target, Clang is used as the C compiler and the assembler.
See below "Building for Windows ARM64" section.

Cross Compiling
---------------
Expand All @@ -57,10 +60,12 @@ that the current beta and nightly releases work.

On Windows, *ring* supports the x86_64-pc-windows-msvc and i686-pc-windows-msvc
targets best. These targets require the “Visual C++ Build Tools
2015” package or Visual Studio 2015 Update 3 or later to be installed. Patches
to get it working on other variants, including in particular Visual Studio 2017
([#338]), Windows ARM platforms, Windows Universal Platform, Windows XP (the
v140_xp toolchain; [#339]), and the -gnu targets ([#330]) are welcome.
2015” package or Visual Studio 2015 Update 3 or later to be installed.
*ring* now also supports the aarch64-pc-windows-msvc target. For the detailed
instructions please see the next section.
Patches to get it working on other variants, including in particular Visual Studio 2017
([#338]), Windows Universal Platform, Windows XP (the v140_xp toolchain; [#339]),
and the -gnu targets ([#330]) are welcome.

For other platforms, GCC 4.6 or later and Clang 3.5 or later are currently
supported best. The build script passes options to the C/C++ compiler that are
Expand All @@ -78,6 +83,34 @@ defined with a value of at least 21 on 64-bit targets or 18 on 32-bit targets;
e.g. export `CFLAGS=-D__ANDROID_API__=21`.


Building for Windows ARM64
--------------------------

Windows ARM64 target requires the “Visual C++ Build Tools 2019” package or
Visual Studio 2019 or later to be installed. “Desktop development with C++”
workflow should be installed, as well as
“MSVC v142 - VS 2019 C++ ARM64 build tools” component.

To build *ring* for Windows ARM64, you will need to install Clang as it is used
as the C compiler and the assembler for that platform. You can either use
the version of Clang installed by Visual Studio, a standalone version from
llvm.org, or a mingw64 version of Clang, for example, from [llvm-mingw
project](https://github.com/mstorsjo/llvm-mingw).

If you're buiding *ring* on an ARM64 device like Surface Pro X, please note
that llvm.org and llvm-mingw have native ARM64 versions of Clang available.
Also, if you're building *ring* on an ARM64 device, you might want to use
`aarch64-pc-windows-msvc` Rustup toolchain, which can be installed using
`rustup toolchain add aarch64-pc-windows-msvc`.

When building on an ARM64 device, due to a bug in the Visual Studio installer,
if you're using `rustc` version < 1.55 you would need to run `cargo build` /
`cargo test` commands from x86_arm64 Developer Command Prompt. You can use
`C:\Program Files (x86)\Microsoft Visual Studio\2019\<edition>\VC\Auxiliary\Build\vcvarsx86_arm64.bat`
batch script to configure the environment. If you use `rustc` 1.55 beta or newer,
you can run `cargo` commands without configuring the dev environment beforehand.


Additional Features that are Useful for Development
---------------------------------------------------
The `slow_tests` feature runs additional tests that are too slow to run during
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ name = "ring"
[dependencies]
untrusted = { version = "0.9" }

[target.'cfg(any(target_arch = "x86",target_arch = "x86_64", all(any(target_arch = "aarch64", target_arch = "arm"), any(target_os = "android", target_os = "fuchsia", target_os = "linux"))))'.dependencies]
[target.'cfg(any(target_arch = "x86",target_arch = "x86_64", all(any(target_arch = "aarch64", target_arch = "arm"), any(target_os = "android", target_os = "fuchsia", target_os = "linux", target_os = "windows"))))'.dependencies]
spin = { version = "0.9.2", default-features = false, features = ["once"] }

[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
Expand All @@ -176,7 +176,7 @@ once_cell = { version = "1.5.2", default-features = false, features=["std"] }
web-sys = { version = "0.3.37", default-features = false, features = ["Crypto", "Window"] }

[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.8", default-features = false, features = ["ntsecapi", "wtypesbase"] }
winapi = { version = "0.3.9", default-features = false, features = ["ntsecapi", "wtypesbase", "processthreadsapi"] }

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = { version = "0.3.18", default-features = false }
Expand Down
70 changes: 34 additions & 36 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,13 @@ const ASM_TARGETS: &[AsmTarget] = &[
asm_extension: "asm",
preassemble: true,
},
AsmTarget {
oss: &[WINDOWS],
arch: "aarch64",
perlasm_format: "win64",
asm_extension: "S",
preassemble: true,
},
];

struct AsmTarget {
Expand Down Expand Up @@ -378,7 +385,7 @@ fn pregenerate_asm_main() {
let os = WINDOWS;

if !std::mem::replace(&mut generated_prefix_headers, true) {
generate_prefix_symbols_nasm(&pregenerated, &ring_core_prefix()).unwrap();
generate_prefix_symbols(&pregenerated, &ring_core_prefix()).unwrap();
}
let srcs = asm_srcs(perlasm_src_dsts);

Expand All @@ -390,10 +397,8 @@ fn pregenerate_asm_main() {
force_warnings_into_errors: true,
};

let compiler = cc::Build::new().get_compiler();

for src in srcs {
compile(&src, &target, &compiler, &pregenerated);
compile(&src, &target, &pregenerated);
}
}
}
Expand Down Expand Up @@ -441,7 +446,7 @@ fn build_c_code(
out_dir
};

generate_prefix_symbols(target, out_dir, ring_core_prefix).unwrap();
generate_prefix_symbols(out_dir, ring_core_prefix).unwrap();

let asm_srcs = if let Some(asm_target) = asm_target {
let perlasm_src_dsts = perlasm_src_dsts(asm_dir, asm_target);
Expand Down Expand Up @@ -500,13 +505,11 @@ fn build_library(
srcs: &[PathBuf],
additional_srcs: &[PathBuf],
) {
let compiler = cc::Build::default().get_compiler();

// Compile all the (dirty) source files into object files.
let objs = additional_srcs
.iter()
.chain(srcs.iter())
.map(|f| compile(f, target, &compiler, out_dir))
.map(|f| compile(f, target, out_dir))
.collect::<Vec<_>>();

// Rebuild the library if necessary.
Expand Down Expand Up @@ -545,14 +548,14 @@ fn build_library(
println!("cargo:rustc-link-lib=static={}", lib_name);
}

fn compile(p: &Path, target: &Target, compiler: &cc::Tool, out_dir: &Path) -> String {
fn compile(p: &Path, target: &Target, out_dir: &Path) -> String {
let ext = p.extension().unwrap().to_str().unwrap();
if ext == "o" {
p.to_str().expect("Invalid path").into()
} else {
let out_path = obj_path(out_dir, p);
let cmd = if target.os != WINDOWS || ext != "asm" {
cc(p, ext, target, compiler, &out_path, out_dir)
cc(p, ext, target, &out_path, out_dir)
} else {
nasm(p, &target.arch, &out_path, out_dir)
};
Expand All @@ -571,27 +574,28 @@ fn obj_path(out_dir: &Path, src: &Path) -> PathBuf {
out_path
}

fn cc(
file: &Path,
ext: &str,
target: &Target,
compiler: &cc::Tool,
out_path: &Path,
include_dir: &Path,
) -> Command {
fn cc(file: &Path, ext: &str, target: &Target, out_path: &Path, include_dir: &Path) -> Command {
let mut c = cc::Build::new();

// FIXME: On Windows AArch64 we currently must use Clang to compile C code
if target.os == WINDOWS && target.arch == AARCH64 && !c.get_compiler().is_like_clang() {
let _ = c.compiler("clang");
}

let compiler = c.get_compiler();

let _ = c.include("include");
let _ = c.include(include_dir);
match ext {
"c" => {
for f in c_flags(compiler) {
for f in c_flags(&compiler) {
let _ = c.flag(f);
}
}
"S" => (),
e => panic!("Unsupported file extension: {:?}", e),
};
for f in cpp_flags(compiler) {
for f in cpp_flags(&compiler) {
let _ = c.flag(f);
}
if target.os != "none"
Expand Down Expand Up @@ -843,24 +847,18 @@ fn ring_core_prefix() -> String {

/// Creates the necessary header file for symbol renaming and returns the path of the
/// generated include directory.
fn generate_prefix_symbols(
target: &Target,
out_dir: &Path,
prefix: &str,
) -> Result<(), std::io::Error> {
fn generate_prefix_symbols(out_dir: &Path, prefix: &str) -> Result<(), std::io::Error> {
generate_prefix_symbols_header(out_dir, "prefix_symbols.h", '#', None, prefix)?;

if target.os == "windows" {
let _ = generate_prefix_symbols_nasm(out_dir, prefix)?;
} else {
generate_prefix_symbols_header(
out_dir,
"prefix_symbols_asm.h",
'#',
Some("#if defined(__APPLE__)"),
prefix,
)?;
}
generate_prefix_symbols_nasm(out_dir, prefix)?;

generate_prefix_symbols_header(
out_dir,
"prefix_symbols_asm.h",
'#',
Some("#if defined(__APPLE__)"),
prefix,
)?;

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion crypto/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <ring-core/cpu.h>
#include "internal.h"

#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
// Our assembly does not use the GOT to reference symbols, which means
// references to visible symbols will often require a TEXTREL. This is
// undesirable, so all assembly-referenced symbols should be hidden. CPU
Expand All @@ -26,7 +27,6 @@
#define HIDDEN __attribute__((visibility("hidden")))
#endif

#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
// This value must be explicitly initialised to zero in order to work around a
// bug in libtool or the linker on OS X.
//
Expand Down
2 changes: 1 addition & 1 deletion crypto/fipsmodule/ec/ecp_nistz384.inl
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,6 @@ void nistz384_point_mul(P384_POINT *r, const BN_ULONG p_scalar[P384_LIMBS],
add_precomputed_w5(r, wvalue, table);
}

#if defined(__GNUC__)
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
3 changes: 2 additions & 1 deletion mk/package.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ if [[ $(git status --porcelain | wc -c) -ne 0 ]]; then
fi

cargo clean --target-dir=target/pregenerate_asm
RING_PREGENERATE_ASM=1 cargo build --target-dir=target/pregenerate_asm
RING_PREGENERATE_ASM=1 CC_AARCH64_PC_WINDOWS_MSVC=clang \
cargo build --target-dir=target/pregenerate_asm
cargo package --allow-dirty
42 changes: 39 additions & 3 deletions src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ pub(crate) fn features() -> Features {
target_arch = "x86_64",
all(
any(target_arch = "aarch64", target_arch = "arm"),
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows"
)
)
))]
{
Expand All @@ -49,7 +54,12 @@ pub(crate) fn features() -> Features {

#[cfg(all(
any(target_arch = "aarch64", target_arch = "arm"),
any(target_os = "android", target_os = "fuchsia", target_os = "linux")
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows"
)
))]
{
arm::setup();
Expand Down Expand Up @@ -162,6 +172,27 @@ pub(crate) mod arm {
}
}

#[cfg(all(target_os = "windows", target_arch = "aarch64"))]
pub fn setup() {
// We do not need to check for the presence of NEON, as Armv8-A always has it
let mut features = NEON.mask;

let result = unsafe {
winapi::um::processthreadsapi::IsProcessorFeaturePresent(
winapi::um::winnt::PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE,
)
};

if result != 0 {
// These are all covered by one call in Windows
features |= AES.mask;
features |= PMULL.mask;
features |= SHA256.mask;
}

unsafe { OPENSSL_armcap_P = features };
}

macro_rules! features {
{
$(
Expand Down Expand Up @@ -237,7 +268,12 @@ pub(crate) mod arm {
}

#[cfg(all(
any(target_os = "android", target_os = "fuchsia", target_os = "linux"),
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows"
),
any(target_arch = "arm", target_arch = "aarch64")
))]
{
Expand Down

0 comments on commit e8e9a67

Please sign in to comment.