targets. There is no case where we have .S files for -msvc targets, so this filter doesn't filter anything out. IIRC, this is stale code from when the situation was different in the past. This reduces the amount of logic that is specific to "-msvc" targets and makes the work to support clang and clang-cl for Windows, and to support AAarch64 Windows, easier to review.
1001 lines
30 KiB
Rust
1001 lines
30 KiB
Rust
// Copyright 2015-2016 Brian Smith.
|
|
//
|
|
// Permission to use, copy, modify, and/or distribute this software for any
|
|
// purpose with or without fee is hereby granted, provided that the above
|
|
// copyright notice and this permission notice appear in all copies.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
|
|
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
//! Build the non-Rust components.
|
|
|
|
// It seems like it would be a good idea to use `log!` for logging, but it
|
|
// isn't worth having the external dependencies (one for the `log` crate, and
|
|
// another for the concrete logging implementation). Instead we use `eprintln!`
|
|
// to log everything to stderr.
|
|
|
|
use std::{
|
|
fs::{self, DirEntry},
|
|
io::Write,
|
|
path::{Path, PathBuf},
|
|
process::Command,
|
|
};
|
|
|
|
const X86: &str = "x86";
|
|
const X86_64: &str = "x86_64";
|
|
const AARCH64: &str = "aarch64";
|
|
const ARM: &str = "arm";
|
|
|
|
#[rustfmt::skip]
|
|
const RING_SRCS: &[(&[&str], &str)] = &[
|
|
(&[], "crypto/fipsmodule/aes/aes_nohw.c"),
|
|
(&[], "crypto/fipsmodule/bn/montgomery.c"),
|
|
(&[], "crypto/fipsmodule/bn/montgomery_inv.c"),
|
|
(&[], "crypto/limbs/limbs.c"),
|
|
(&[], "crypto/mem.c"),
|
|
(&[], "crypto/poly1305/poly1305.c"),
|
|
|
|
(&[AARCH64, ARM, X86_64, X86], "crypto/crypto.c"),
|
|
(&[AARCH64, ARM, X86_64, X86], "crypto/curve25519/curve25519.c"),
|
|
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/ecp_nistz.c"),
|
|
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/gfp_p256.c"),
|
|
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/gfp_p384.c"),
|
|
(&[AARCH64, ARM, X86_64, X86], "crypto/fipsmodule/ec/p256.c"),
|
|
|
|
(&[X86_64, X86], "crypto/cpu-intel.c"),
|
|
|
|
(&[X86], "crypto/fipsmodule/aes/asm/aesni-x86.pl"),
|
|
(&[X86], "crypto/fipsmodule/aes/asm/vpaes-x86.pl"),
|
|
(&[X86], "crypto/fipsmodule/bn/asm/x86-mont.pl"),
|
|
(&[X86], "crypto/chacha/asm/chacha-x86.pl"),
|
|
(&[X86], "crypto/fipsmodule/modes/asm/ghash-x86.pl"),
|
|
|
|
(&[X86_64], "crypto/chacha/asm/chacha-x86_64.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/aes/asm/aesni-x86_64.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/aes/asm/vpaes-x86_64.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/bn/asm/x86_64-mont.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/bn/asm/x86_64-mont5.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/ec/p256-x86_64.c"),
|
|
(&[X86_64], "crypto/fipsmodule/ec/asm/p256-x86_64-asm.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/modes/asm/aesni-gcm-x86_64.pl"),
|
|
(&[X86_64], "crypto/fipsmodule/modes/asm/ghash-x86_64.pl"),
|
|
(&[X86_64], "crypto/poly1305/poly1305_vec.c"),
|
|
(&[X86_64], SHA512_X86_64),
|
|
(&[X86_64], "crypto/cipher_extra/asm/chacha20_poly1305_x86_64.pl"),
|
|
|
|
(&[AARCH64, ARM], "crypto/fipsmodule/aes/asm/aesv8-armx.pl"),
|
|
(&[AARCH64, ARM], "crypto/fipsmodule/modes/asm/ghashv8-armx.pl"),
|
|
|
|
(&[ARM], "crypto/fipsmodule/aes/asm/bsaes-armv7.pl"),
|
|
(&[ARM], "crypto/fipsmodule/aes/asm/vpaes-armv7.pl"),
|
|
(&[ARM], "crypto/fipsmodule/bn/asm/armv4-mont.pl"),
|
|
(&[ARM], "crypto/chacha/asm/chacha-armv4.pl"),
|
|
(&[ARM], "crypto/curve25519/asm/x25519-asm-arm.S"),
|
|
(&[ARM], "crypto/fipsmodule/modes/asm/ghash-armv4.pl"),
|
|
(&[ARM], "crypto/poly1305/poly1305_arm.c"),
|
|
(&[ARM], "crypto/poly1305/poly1305_arm_asm.S"),
|
|
(&[ARM], "crypto/fipsmodule/sha/asm/sha256-armv4.pl"),
|
|
(&[ARM], "crypto/fipsmodule/sha/asm/sha512-armv4.pl"),
|
|
|
|
(&[AARCH64], "crypto/fipsmodule/aes/asm/vpaes-armv8.pl"),
|
|
(&[AARCH64], "crypto/fipsmodule/bn/asm/armv8-mont.pl"),
|
|
(&[AARCH64], "crypto/chacha/asm/chacha-armv8.pl"),
|
|
(&[AARCH64], "crypto/fipsmodule/modes/asm/ghash-neon-armv8.pl"),
|
|
(&[AARCH64], SHA512_ARMV8),
|
|
];
|
|
|
|
const SHA256_X86_64: &str = "crypto/fipsmodule/sha/asm/sha256-x86_64.pl";
|
|
const SHA512_X86_64: &str = "crypto/fipsmodule/sha/asm/sha512-x86_64.pl";
|
|
|
|
const SHA256_ARMV8: &str = "crypto/fipsmodule/sha/asm/sha256-armv8.pl";
|
|
const SHA512_ARMV8: &str = "crypto/fipsmodule/sha/asm/sha512-armv8.pl";
|
|
|
|
const RING_TEST_SRCS: &[&str] = &[("crypto/constant_time_test.c")];
|
|
|
|
const PREGENERATED: &str = "pregenerated";
|
|
|
|
fn c_flags(target: &Target) -> &'static [&'static str] {
|
|
if target.env != MSVC {
|
|
static NON_MSVC_FLAGS: &[&str] = &[
|
|
"-std=c1x", // GCC 4.6 requires "c1x" instead of "c11"
|
|
"-Wbad-function-cast",
|
|
"-Wnested-externs",
|
|
"-Wstrict-prototypes",
|
|
];
|
|
NON_MSVC_FLAGS
|
|
} else {
|
|
&[]
|
|
}
|
|
}
|
|
|
|
fn cpp_flags(target: &Target) -> &'static [&'static str] {
|
|
if target.env != MSVC {
|
|
static NON_MSVC_FLAGS: &[&str] = &[
|
|
"-pedantic",
|
|
"-pedantic-errors",
|
|
"-Wall",
|
|
"-Wextra",
|
|
"-Wcast-align",
|
|
"-Wcast-qual",
|
|
"-Wconversion",
|
|
"-Wenum-compare",
|
|
"-Wfloat-equal",
|
|
"-Wformat=2",
|
|
"-Winline",
|
|
"-Winvalid-pch",
|
|
"-Wmissing-field-initializers",
|
|
"-Wmissing-include-dirs",
|
|
"-Wredundant-decls",
|
|
"-Wshadow",
|
|
"-Wsign-compare",
|
|
"-Wsign-conversion",
|
|
"-Wundef",
|
|
"-Wuninitialized",
|
|
"-Wwrite-strings",
|
|
"-fno-strict-aliasing",
|
|
"-fvisibility=hidden",
|
|
];
|
|
NON_MSVC_FLAGS
|
|
} else {
|
|
static MSVC_FLAGS: &[&str] = &[
|
|
"/GS", // Buffer security checks.
|
|
"/Gy", // Enable function-level linking.
|
|
"/EHsc", // C++ exceptions only, only in C++.
|
|
"/GR-", // Disable RTTI.
|
|
"/Zc:wchar_t",
|
|
"/Zc:forScope",
|
|
"/Zc:inline",
|
|
"/Zc:rvalueCast",
|
|
// Warnings.
|
|
"/sdl",
|
|
"/Wall",
|
|
"/wd4127", // C4127: conditional expression is constant
|
|
"/wd4464", // C4464: relative include path contains '..'
|
|
"/wd4514", // C4514: <name>: unreferenced inline function has be
|
|
"/wd4710", // C4710: function not inlined
|
|
"/wd4711", // C4711: function 'function' selected for inline expansion
|
|
"/wd4820", // C4820: <struct>: <n> bytes padding added after <name>
|
|
"/wd5045", /* C5045: Compiler will insert Spectre mitigation for memory load if
|
|
* /Qspectre switch specified */
|
|
];
|
|
MSVC_FLAGS
|
|
}
|
|
}
|
|
|
|
const LD_FLAGS: &[&str] = &[];
|
|
|
|
// None means "any OS" or "any target". The first match in sequence order is
|
|
// taken.
|
|
const ASM_TARGETS: &[AsmTarget] = &[
|
|
AsmTarget {
|
|
oss: LINUX_ABI,
|
|
arch: "aarch64",
|
|
perlasm_format: "linux64",
|
|
asm_extension: "S",
|
|
preassemble: false,
|
|
},
|
|
AsmTarget {
|
|
oss: LINUX_ABI,
|
|
arch: "arm",
|
|
perlasm_format: "linux32",
|
|
asm_extension: "S",
|
|
preassemble: false,
|
|
},
|
|
AsmTarget {
|
|
oss: LINUX_ABI,
|
|
arch: "x86",
|
|
perlasm_format: "elf",
|
|
asm_extension: "S",
|
|
preassemble: false,
|
|
},
|
|
AsmTarget {
|
|
oss: LINUX_ABI,
|
|
arch: "x86_64",
|
|
perlasm_format: "elf",
|
|
asm_extension: "S",
|
|
preassemble: false,
|
|
},
|
|
AsmTarget {
|
|
oss: MACOS_ABI,
|
|
arch: "aarch64",
|
|
perlasm_format: "ios64",
|
|
asm_extension: "S",
|
|
preassemble: false,
|
|
},
|
|
AsmTarget {
|
|
oss: MACOS_ABI,
|
|
arch: "x86_64",
|
|
perlasm_format: "macosx",
|
|
asm_extension: "S",
|
|
preassemble: false,
|
|
},
|
|
AsmTarget {
|
|
oss: &[WINDOWS],
|
|
arch: "x86",
|
|
perlasm_format: "win32n",
|
|
asm_extension: "asm",
|
|
preassemble: true,
|
|
},
|
|
AsmTarget {
|
|
oss: &[WINDOWS],
|
|
arch: "x86_64",
|
|
perlasm_format: "nasm",
|
|
asm_extension: "asm",
|
|
preassemble: true,
|
|
},
|
|
];
|
|
|
|
struct AsmTarget {
|
|
/// Operating systems.
|
|
oss: &'static [&'static str],
|
|
|
|
/// Architectures.
|
|
arch: &'static str,
|
|
|
|
/// The PerlAsm format name.
|
|
perlasm_format: &'static str,
|
|
|
|
/// The filename extension for assembly files.
|
|
asm_extension: &'static str,
|
|
|
|
/// Whether pre-assembled object files should be included in the Cargo
|
|
/// package instead of the asm sources. This way, the user doesn't need
|
|
/// to install an assembler for the target. This is particularly important
|
|
/// for x86/x86_64 Windows since an assembler doesn't come with the C
|
|
/// compiler.
|
|
preassemble: bool,
|
|
}
|
|
|
|
/// Operating systems that have the same ABI as Linux on every architecture
|
|
/// mentioned in `ASM_TARGETS`.
|
|
const LINUX_ABI: &[&str] = &[
|
|
"android",
|
|
"dragonfly",
|
|
"freebsd",
|
|
"fuchsia",
|
|
"illumos",
|
|
"netbsd",
|
|
"openbsd",
|
|
"linux",
|
|
"solaris",
|
|
];
|
|
|
|
/// Operating systems that have the same ABI as macOS on every architecture
|
|
/// mentioned in `ASM_TARGETS`.
|
|
const MACOS_ABI: &[&str] = &["ios", "macos"];
|
|
|
|
const WINDOWS: &str = "windows";
|
|
|
|
const MSVC: &str = "msvc";
|
|
const MSVC_OBJ_OPT: &str = "/Fo";
|
|
|
|
/// Read an environment variable and tell Cargo that we depend on it.
|
|
///
|
|
/// This needs to be used for any environment variable that isn't a standard
|
|
/// Cargo-supplied variable.
|
|
///
|
|
/// The name is static since we intend to only read a static set of environment
|
|
/// variables.
|
|
fn read_env_var(name: &'static str) -> Result<String, std::env::VarError> {
|
|
println!("cargo:rerun-if-env-changed={}", name);
|
|
std::env::var(name)
|
|
}
|
|
|
|
fn main() {
|
|
const RING_PREGENERATE_ASM: &str = "RING_PREGENERATE_ASM";
|
|
match read_env_var(RING_PREGENERATE_ASM).as_deref() {
|
|
Ok("1") => {
|
|
pregenerate_asm_main();
|
|
}
|
|
Err(std::env::VarError::NotPresent) => ring_build_rs_main(),
|
|
_ => {
|
|
panic!("${} has an invalid value", RING_PREGENERATE_ASM);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn ring_build_rs_main() {
|
|
use std::env;
|
|
|
|
let out_dir = env::var("OUT_DIR").unwrap();
|
|
let out_dir = PathBuf::from(out_dir);
|
|
|
|
let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
|
let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
|
|
let obj_opt = if env == MSVC { MSVC_OBJ_OPT } else { "-o" };
|
|
|
|
let is_git = std::fs::metadata(".git").is_ok();
|
|
|
|
// Published builds are always release builds.
|
|
let is_debug = is_git && env::var("DEBUG").unwrap() != "false";
|
|
|
|
let target = Target {
|
|
arch,
|
|
os,
|
|
env,
|
|
obj_opt,
|
|
is_git,
|
|
is_debug,
|
|
};
|
|
let pregenerated = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join(PREGENERATED);
|
|
|
|
build_c_code(&target, pregenerated, &out_dir, &ring_core_prefix());
|
|
emit_rerun_if_changed()
|
|
}
|
|
|
|
fn pregenerate_asm_main() {
|
|
println!("cargo:rustc-cfg=pregenerate_asm_only");
|
|
|
|
let pregenerated = PathBuf::from(PREGENERATED);
|
|
std::fs::create_dir(&pregenerated).unwrap();
|
|
let pregenerated_tmp = pregenerated.join("tmp");
|
|
std::fs::create_dir(&pregenerated_tmp).unwrap();
|
|
|
|
let mut generated_prefix_headers = false;
|
|
|
|
for asm_target in ASM_TARGETS {
|
|
// For Windows, package pregenerated object files instead of
|
|
// pregenerated assembly language source files, so that the user
|
|
// doesn't need to install the assembler.
|
|
let asm_dir = if asm_target.preassemble {
|
|
&pregenerated_tmp
|
|
} else {
|
|
&pregenerated
|
|
};
|
|
|
|
let perlasm_src_dsts = perlasm_src_dsts(asm_dir, asm_target);
|
|
perlasm(&perlasm_src_dsts, asm_target);
|
|
|
|
if asm_target.preassemble {
|
|
if !std::mem::replace(&mut generated_prefix_headers, true) {
|
|
generate_prefix_symbols_nasm(&pregenerated, &ring_core_prefix()).unwrap();
|
|
}
|
|
let srcs = asm_srcs(perlasm_src_dsts);
|
|
for src in srcs {
|
|
let obj_path = obj_path(&pregenerated, &src);
|
|
run_command(nasm(&src, asm_target.arch, &obj_path, &pregenerated));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct Target {
|
|
arch: String,
|
|
os: String,
|
|
env: String,
|
|
obj_opt: &'static str,
|
|
is_git: bool,
|
|
is_debug: bool,
|
|
}
|
|
|
|
fn build_c_code(target: &Target, pregenerated: PathBuf, out_dir: &Path, ring_core_prefix: &str) {
|
|
println!("cargo:rustc-env=RING_CORE_PREFIX={}", ring_core_prefix);
|
|
|
|
#[cfg(not(feature = "wasm32_c"))]
|
|
{
|
|
if &target.arch == "wasm32" {
|
|
return;
|
|
}
|
|
}
|
|
|
|
let asm_target = ASM_TARGETS.iter().find(|asm_target| {
|
|
asm_target.arch == target.arch && asm_target.oss.contains(&target.os.as_ref())
|
|
});
|
|
|
|
let use_pregenerated = !target.is_git;
|
|
let warnings_are_errors = target.is_git;
|
|
|
|
let asm_dir = if use_pregenerated {
|
|
&pregenerated
|
|
} else {
|
|
out_dir
|
|
};
|
|
|
|
generate_prefix_symbols(target, 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);
|
|
|
|
if !use_pregenerated {
|
|
perlasm(&perlasm_src_dsts[..], asm_target);
|
|
}
|
|
|
|
let mut asm_srcs = asm_srcs(perlasm_src_dsts);
|
|
|
|
// For Windows we also pregenerate the object files for non-Git builds so
|
|
// the user doesn't need to install the assembler. On other platforms we
|
|
// assume the C compiler also assembles.
|
|
if use_pregenerated && target.os == WINDOWS {
|
|
asm_srcs = asm_srcs
|
|
.iter()
|
|
.map(|src| obj_path(&pregenerated, src.as_path()))
|
|
.collect::<Vec<_>>();
|
|
}
|
|
|
|
asm_srcs
|
|
} else {
|
|
Vec::new()
|
|
};
|
|
|
|
let core_srcs = sources_for_arch(&target.arch)
|
|
.into_iter()
|
|
.filter(|p| !is_perlasm(p))
|
|
.collect::<Vec<_>>();
|
|
|
|
let test_srcs = RING_TEST_SRCS.iter().map(PathBuf::from).collect::<Vec<_>>();
|
|
|
|
let libs = [
|
|
("", &core_srcs[..], &asm_srcs[..]),
|
|
("test", &test_srcs[..], &[]),
|
|
];
|
|
|
|
// XXX: Ideally, ring-test would only be built for `cargo test`, but Cargo
|
|
// can't do that yet.
|
|
libs.iter()
|
|
.for_each(|&(lib_name_suffix, srcs, additional_srcs)| {
|
|
let lib_name = String::from(ring_core_prefix) + lib_name_suffix;
|
|
build_library(
|
|
target,
|
|
out_dir,
|
|
&lib_name,
|
|
srcs,
|
|
additional_srcs,
|
|
warnings_are_errors,
|
|
)
|
|
});
|
|
|
|
println!(
|
|
"cargo:rustc-link-search=native={}",
|
|
out_dir.to_str().expect("Invalid path")
|
|
);
|
|
}
|
|
|
|
fn build_library(
|
|
target: &Target,
|
|
out_dir: &Path,
|
|
lib_name: &str,
|
|
srcs: &[PathBuf],
|
|
additional_srcs: &[PathBuf],
|
|
warnings_are_errors: bool,
|
|
) {
|
|
// Compile all the (dirty) source files into object files.
|
|
let objs = additional_srcs
|
|
.iter()
|
|
.chain(srcs.iter())
|
|
.map(|f| compile(f, target, warnings_are_errors, out_dir))
|
|
.collect::<Vec<_>>();
|
|
|
|
// Rebuild the library if necessary.
|
|
let lib_path = PathBuf::from(out_dir).join(format!("lib{}.a", lib_name));
|
|
|
|
let mut c = cc::Build::new();
|
|
|
|
for f in LD_FLAGS {
|
|
let _ = c.flag(f);
|
|
}
|
|
match target.os.as_str() {
|
|
"macos" => {
|
|
let _ = c.flag("-fPIC");
|
|
let _ = c.flag("-Wl,-dead_strip");
|
|
}
|
|
_ => {
|
|
let _ = c.flag("-Wl,--gc-sections");
|
|
}
|
|
}
|
|
for o in objs {
|
|
let _ = c.object(o);
|
|
}
|
|
|
|
// Handled below.
|
|
let _ = c.cargo_metadata(false);
|
|
|
|
c.compile(
|
|
lib_path
|
|
.file_name()
|
|
.and_then(|f| f.to_str())
|
|
.expect("No filename"),
|
|
);
|
|
|
|
// Link the library. This works even when the library doesn't need to be
|
|
// rebuilt.
|
|
println!("cargo:rustc-link-lib=static={}", lib_name);
|
|
}
|
|
|
|
fn compile(p: &Path, target: &Target, warnings_are_errors: bool, 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, warnings_are_errors, &out_path, out_dir)
|
|
} else {
|
|
nasm(p, &target.arch, &out_path, out_dir)
|
|
};
|
|
|
|
run_command(cmd);
|
|
out_path.to_str().expect("Invalid path").into()
|
|
}
|
|
}
|
|
|
|
fn obj_path(out_dir: &Path, src: &Path) -> PathBuf {
|
|
let mut out_path = out_dir.join(src.file_name().unwrap());
|
|
// To eliminate unnecessary conditional logic, use ".o" as the extension,
|
|
// even when the compiler (e.g. MSVC) would normally use something else
|
|
// (e.g. ".obj"). cc-rs seems to do the same.
|
|
assert!(out_path.set_extension("o"));
|
|
out_path
|
|
}
|
|
|
|
fn cc(
|
|
file: &Path,
|
|
ext: &str,
|
|
target: &Target,
|
|
warnings_are_errors: bool,
|
|
out_path: &Path,
|
|
include_dir: &Path,
|
|
) -> Command {
|
|
let is_musl = target.env.starts_with("musl");
|
|
|
|
let mut c = cc::Build::new();
|
|
let _ = c.include("include");
|
|
let _ = c.include(include_dir);
|
|
match ext {
|
|
"c" => {
|
|
for f in c_flags(target) {
|
|
let _ = c.flag(f);
|
|
}
|
|
}
|
|
"S" => (),
|
|
e => panic!("Unsupported file extension: {:?}", e),
|
|
};
|
|
for f in cpp_flags(target) {
|
|
let _ = c.flag(f);
|
|
}
|
|
if target.os != "none"
|
|
&& target.os != "redox"
|
|
&& target.os != "windows"
|
|
&& target.arch != "wasm32"
|
|
{
|
|
let _ = c.flag("-fstack-protector");
|
|
}
|
|
|
|
match (target.os.as_str(), target.env.as_str()) {
|
|
// ``-gfull`` is required for Darwin's |-dead_strip|.
|
|
("macos", _) => {
|
|
let _ = c.flag("-gfull");
|
|
}
|
|
(_, "msvc") => (),
|
|
_ => {
|
|
let _ = c.flag("-g3");
|
|
}
|
|
};
|
|
if !target.is_debug {
|
|
let _ = c.define("NDEBUG", None);
|
|
}
|
|
|
|
if &target.env == "msvc" {
|
|
if std::env::var("OPT_LEVEL").unwrap() == "0" {
|
|
let _ = c.flag("/Od"); // Disable optimization for debug builds.
|
|
// run-time checking: (s)tack frame, (u)ninitialized variables
|
|
let _ = c.flag("/RTCsu");
|
|
} else {
|
|
let _ = c.flag("/Ox"); // Enable full optimization.
|
|
}
|
|
}
|
|
|
|
// Allow cross-compiling without a target sysroot for these targets.
|
|
//
|
|
// poly1305_vec.c requires <emmintrin.h> which requires <stdlib.h>.
|
|
if (target.arch == "wasm32" && target.os == "unknown")
|
|
|| (target.os == "linux" && is_musl && target.arch != "x86_64")
|
|
{
|
|
if let Ok(compiler) = c.try_get_compiler() {
|
|
// TODO: Expand this to non-clang compilers in 0.17.0 if practical.
|
|
if compiler.is_like_clang() {
|
|
let _ = c.flag("-nostdlibinc");
|
|
let _ = c.define("RING_CORE_NOSTDLIBINC", "1");
|
|
}
|
|
}
|
|
}
|
|
|
|
if warnings_are_errors {
|
|
c.warnings_into_errors(true);
|
|
}
|
|
if is_musl {
|
|
// Some platforms enable _FORTIFY_SOURCE by default, but musl
|
|
// libc doesn't support it yet. See
|
|
// http://wiki.musl-libc.org/wiki/Future_Ideas#Fortify
|
|
// http://www.openwall.com/lists/musl/2015/02/04/3
|
|
// http://www.openwall.com/lists/musl/2015/06/17/1
|
|
let _ = c.flag("-U_FORTIFY_SOURCE");
|
|
}
|
|
|
|
let mut c = c.get_compiler().to_command();
|
|
let _ = c
|
|
.arg("-c")
|
|
.arg(format!(
|
|
"{}{}",
|
|
target.obj_opt,
|
|
out_path.to_str().expect("Invalid path")
|
|
))
|
|
.arg(file);
|
|
c
|
|
}
|
|
|
|
fn nasm(file: &Path, arch: &str, out_file: &Path, include_dir: &Path) -> Command {
|
|
let oformat = match arch {
|
|
"x86_64" => ("win64"),
|
|
"x86" => ("win32"),
|
|
_ => panic!("unsupported arch: {}", arch),
|
|
};
|
|
|
|
// Nasm requires that the path end in a path separator.
|
|
let mut include_dir = include_dir.as_os_str().to_os_string();
|
|
include_dir.push(std::ffi::OsString::from(String::from(
|
|
std::path::MAIN_SEPARATOR,
|
|
)));
|
|
|
|
let mut c = Command::new("./target/tools/windows/nasm/nasm");
|
|
let _ = c
|
|
.arg("-o")
|
|
.arg(out_file.to_str().expect("Invalid path"))
|
|
.arg("-f")
|
|
.arg(oformat)
|
|
.arg("-i")
|
|
.arg("include/")
|
|
.arg("-i")
|
|
.arg(include_dir)
|
|
.arg("-Xgnu")
|
|
.arg("-gcv8")
|
|
.arg(file);
|
|
c
|
|
}
|
|
|
|
fn run_command_with_args<S>(command_name: S, args: &[String])
|
|
where
|
|
S: AsRef<std::ffi::OsStr> + Copy,
|
|
{
|
|
let mut cmd = Command::new(command_name);
|
|
let _ = cmd.args(args);
|
|
run_command(cmd)
|
|
}
|
|
|
|
fn run_command(mut cmd: Command) {
|
|
eprintln!("running {:?}", cmd);
|
|
let status = cmd.status().unwrap_or_else(|e| {
|
|
panic!("failed to execute [{:?}]: {}", cmd, e);
|
|
});
|
|
if !status.success() {
|
|
panic!("execution failed");
|
|
}
|
|
}
|
|
|
|
fn sources_for_arch(arch: &str) -> Vec<PathBuf> {
|
|
RING_SRCS
|
|
.iter()
|
|
.filter(|&&(archs, _)| archs.is_empty() || archs.contains(&arch))
|
|
.map(|&(_, p)| PathBuf::from(p))
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
fn perlasm_src_dsts(out_dir: &Path, asm_target: &AsmTarget) -> Vec<(PathBuf, PathBuf)> {
|
|
let srcs = sources_for_arch(asm_target.arch);
|
|
let mut src_dsts = srcs
|
|
.iter()
|
|
.filter(|p| is_perlasm(p))
|
|
.map(|src| (src.clone(), asm_path(out_dir, src, asm_target)))
|
|
.collect::<Vec<_>>();
|
|
|
|
// Some PerlAsm source files need to be run multiple times with different
|
|
// output paths.
|
|
{
|
|
// Appease the borrow checker.
|
|
let mut maybe_synthesize = |concrete, synthesized| {
|
|
let concrete_path = PathBuf::from(concrete);
|
|
if srcs.contains(&concrete_path) {
|
|
let synthesized_path = PathBuf::from(synthesized);
|
|
src_dsts.push((
|
|
concrete_path,
|
|
asm_path(out_dir, &synthesized_path, asm_target),
|
|
))
|
|
}
|
|
};
|
|
maybe_synthesize(SHA512_X86_64, SHA256_X86_64);
|
|
maybe_synthesize(SHA512_ARMV8, SHA256_ARMV8);
|
|
}
|
|
|
|
src_dsts
|
|
}
|
|
|
|
fn asm_srcs(perlasm_src_dsts: Vec<(PathBuf, PathBuf)>) -> Vec<PathBuf> {
|
|
perlasm_src_dsts
|
|
.into_iter()
|
|
.map(|(_src, dst)| dst)
|
|
.collect::<Vec<_>>()
|
|
}
|
|
|
|
fn is_perlasm(path: &PathBuf) -> bool {
|
|
path.extension().unwrap().to_str().unwrap() == "pl"
|
|
}
|
|
|
|
fn asm_path(out_dir: &Path, src: &Path, asm_target: &AsmTarget) -> PathBuf {
|
|
let src_stem = src.file_stem().expect("source file without basename");
|
|
|
|
let dst_stem = src_stem.to_str().unwrap();
|
|
let dst_filename = format!(
|
|
"{}-{}.{}",
|
|
dst_stem, asm_target.perlasm_format, asm_target.asm_extension
|
|
);
|
|
out_dir.join(dst_filename)
|
|
}
|
|
|
|
fn perlasm(src_dst: &[(PathBuf, PathBuf)], asm_target: &AsmTarget) {
|
|
for (src, dst) in src_dst {
|
|
let mut args = vec![
|
|
src.to_string_lossy().into_owned(),
|
|
asm_target.perlasm_format.to_owned(),
|
|
];
|
|
if asm_target.arch == "x86" {
|
|
args.push("-fPIC".into());
|
|
args.push("-DOPENSSL_IA32_SSE2".into());
|
|
}
|
|
// Work around PerlAsm issue for ARM and AAarch64 targets by replacing
|
|
// back slashes with forward slashes.
|
|
let dst = dst
|
|
.to_str()
|
|
.expect("Could not convert path")
|
|
.replace("\\", "/");
|
|
args.push(dst);
|
|
run_command_with_args(&get_command("PERL_EXECUTABLE", "perl"), &args);
|
|
}
|
|
}
|
|
|
|
fn get_command(var: &'static str, default: &str) -> String {
|
|
read_env_var(var).unwrap_or_else(|_| default.into())
|
|
}
|
|
|
|
// TODO: We should emit `cargo:rerun-if-changed-env` for the various
|
|
// environment variables that affect the build.
|
|
fn emit_rerun_if_changed() {
|
|
for path in &["crypto", "include", "third_party/fiat"] {
|
|
walk_dir(&PathBuf::from(path), &|entry| {
|
|
let path = entry.path();
|
|
match path.extension().and_then(|ext| ext.to_str()) {
|
|
Some("c") | Some("S") | Some("h") | Some("inl") | Some("pl") | None => {
|
|
println!("cargo:rerun-if-changed={}", path.to_str().unwrap());
|
|
}
|
|
_ => {
|
|
// Ignore other types of files.
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
fn walk_dir(dir: &Path, cb: &impl Fn(&DirEntry)) {
|
|
if dir.is_dir() {
|
|
for entry in fs::read_dir(dir).unwrap() {
|
|
let entry = entry.unwrap();
|
|
let path = entry.path();
|
|
if path.is_dir() {
|
|
walk_dir(&path, cb);
|
|
} else {
|
|
cb(&entry);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn ring_core_prefix() -> String {
|
|
let links = std::env::var("CARGO_MANIFEST_LINKS").unwrap();
|
|
|
|
let computed = {
|
|
let name = std::env::var("CARGO_PKG_NAME").unwrap();
|
|
let version = std::env::var("CARGO_PKG_VERSION").unwrap();
|
|
name + "_core_" + &version.replace(&['-', '.'][..], "_")
|
|
};
|
|
|
|
assert_eq!(links, computed);
|
|
|
|
links + "_"
|
|
}
|
|
|
|
/// 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> {
|
|
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,
|
|
)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn generate_prefix_symbols_nasm(out_dir: &Path, prefix: &str) -> Result<(), std::io::Error> {
|
|
generate_prefix_symbols_header(
|
|
out_dir,
|
|
"prefix_symbols_nasm.inc",
|
|
'%',
|
|
Some("%ifidn __OUTPUT_FORMAT__,win32"),
|
|
prefix,
|
|
)
|
|
}
|
|
|
|
fn generate_prefix_symbols_header(
|
|
out_dir: &Path,
|
|
filename: &str,
|
|
pp: char,
|
|
prefix_condition: Option<&str>,
|
|
prefix: &str,
|
|
) -> Result<(), std::io::Error> {
|
|
let dir = out_dir.join("ring_core_generated");
|
|
std::fs::create_dir_all(&dir)?;
|
|
|
|
let path = dir.join(filename);
|
|
let mut file = std::fs::File::create(&path)?;
|
|
|
|
let filename_ident = filename.replace(".", "_").to_uppercase();
|
|
writeln!(
|
|
file,
|
|
r#"
|
|
{pp}ifndef ring_core_generated_{filename_ident}
|
|
{pp}define ring_core_generated_{filename_ident}
|
|
"#,
|
|
pp = pp,
|
|
filename_ident = filename_ident
|
|
)?;
|
|
|
|
if let Some(prefix_condition) = prefix_condition {
|
|
writeln!(file, "{}", prefix_condition)?;
|
|
writeln!(file, "{}", prefix_all_symbols(pp, "_", prefix))?;
|
|
writeln!(file, "{pp}else", pp = pp)?;
|
|
};
|
|
writeln!(file, "{}", prefix_all_symbols(pp, "", prefix))?;
|
|
if prefix_condition.is_some() {
|
|
writeln!(file, "{pp}endif", pp = pp)?
|
|
}
|
|
|
|
writeln!(file, "{pp}endif", pp = pp)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn prefix_all_symbols(pp: char, prefix_prefix: &str, prefix: &str) -> String {
|
|
static SYMBOLS_TO_PREFIX: &[&str] = &[
|
|
"CRYPTO_poly1305_finish",
|
|
"CRYPTO_poly1305_finish_neon",
|
|
"CRYPTO_poly1305_init",
|
|
"CRYPTO_poly1305_init_neon",
|
|
"CRYPTO_poly1305_update",
|
|
"CRYPTO_poly1305_update_neon",
|
|
"ChaCha20_ctr32",
|
|
"LIMBS_add_mod",
|
|
"LIMBS_are_even",
|
|
"LIMBS_are_zero",
|
|
"LIMBS_equal",
|
|
"LIMBS_equal_limb",
|
|
"LIMBS_less_than",
|
|
"LIMBS_less_than_limb",
|
|
"LIMBS_reduce_once",
|
|
"LIMBS_select_512_32",
|
|
"LIMBS_shl_mod",
|
|
"LIMBS_sub_mod",
|
|
"LIMBS_window5_split_window",
|
|
"LIMBS_window5_unsplit_window",
|
|
"LIMB_shr",
|
|
"OPENSSL_armcap_P",
|
|
"OPENSSL_cpuid_setup",
|
|
"OPENSSL_ia32cap_P",
|
|
"OPENSSL_memcmp",
|
|
"aes_hw_ctr32_encrypt_blocks",
|
|
"aes_hw_encrypt",
|
|
"aes_hw_set_encrypt_key",
|
|
"aes_nohw_ctr32_encrypt_blocks",
|
|
"aes_nohw_encrypt",
|
|
"aes_nohw_set_encrypt_key",
|
|
"aesni_gcm_decrypt",
|
|
"aesni_gcm_encrypt",
|
|
"bn_from_montgomery",
|
|
"bn_from_montgomery_in_place",
|
|
"bn_gather5",
|
|
"bn_mul_mont",
|
|
"bn_mul_mont_gather5",
|
|
"bn_neg_inv_mod_r_u64",
|
|
"bn_power5",
|
|
"bn_scatter5",
|
|
"bn_sqr8x_internal",
|
|
"bn_sqrx8x_internal",
|
|
"bsaes_ctr32_encrypt_blocks",
|
|
"bssl_constant_time_test_main",
|
|
"chacha20_poly1305_open",
|
|
"chacha20_poly1305_seal",
|
|
"gcm_ghash_avx",
|
|
"gcm_ghash_clmul",
|
|
"gcm_ghash_neon",
|
|
"gcm_gmult_clmul",
|
|
"gcm_gmult_neon",
|
|
"gcm_init_avx",
|
|
"gcm_init_clmul",
|
|
"gcm_init_neon",
|
|
"limbs_mul_add_limb",
|
|
"little_endian_bytes_from_scalar",
|
|
"nistz256_neg",
|
|
"nistz256_select_w5",
|
|
"nistz256_select_w7",
|
|
"nistz384_point_add",
|
|
"nistz384_point_double",
|
|
"nistz384_point_mul",
|
|
"p256_mul_mont",
|
|
"p256_point_add",
|
|
"p256_point_add_affine",
|
|
"p256_point_double",
|
|
"p256_point_mul",
|
|
"p256_point_mul_base",
|
|
"p256_scalar_mul_mont",
|
|
"p256_scalar_sqr_rep_mont",
|
|
"p256_sqr_mont",
|
|
"p384_elem_div_by_2",
|
|
"p384_elem_mul_mont",
|
|
"p384_elem_neg",
|
|
"p384_elem_sub",
|
|
"p384_scalar_mul_mont",
|
|
"openssl_poly1305_neon2_addmulmod",
|
|
"openssl_poly1305_neon2_blocks",
|
|
"sha256_block_data_order",
|
|
"sha512_block_data_order",
|
|
"vpaes_ctr32_encrypt_blocks",
|
|
"vpaes_encrypt",
|
|
"vpaes_encrypt_key_to_bsaes",
|
|
"vpaes_set_encrypt_key",
|
|
"x25519_NEON",
|
|
"x25519_fe_invert",
|
|
"x25519_fe_isnegative",
|
|
"x25519_fe_mul_ttt",
|
|
"x25519_fe_neg",
|
|
"x25519_fe_tobytes",
|
|
"x25519_ge_double_scalarmult_vartime",
|
|
"x25519_ge_frombytes_vartime",
|
|
"x25519_ge_scalarmult_base",
|
|
"x25519_public_from_private_generic_masked",
|
|
"x25519_sc_mask",
|
|
"x25519_sc_muladd",
|
|
"x25519_sc_reduce",
|
|
"x25519_scalar_mult_generic_masked",
|
|
];
|
|
|
|
let mut out = String::new();
|
|
|
|
for symbol in SYMBOLS_TO_PREFIX {
|
|
let line = format!(
|
|
"{pp}define {prefix_prefix}{symbol} {prefix_prefix}{prefix}{symbol}\n",
|
|
pp = pp,
|
|
prefix_prefix = prefix_prefix,
|
|
prefix = prefix,
|
|
symbol = symbol
|
|
);
|
|
out += &line;
|
|
}
|
|
|
|
out
|
|
}
|