use std::{env, fs, path::PathBuf, process::Command}; fn main() { println!("cargo:rerun-if-changed=../runtime-proxy.c"); println!("cargo:rerun-if-env-changed=ARCHY_RUNTIME_PROXY_CC"); let output = PathBuf::from(env::var_os("OUT_DIR").unwrap()).join("archipelago-runtime-proxy"); let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); if env::var("CARGO_CFG_TARGET_OS").unwrap() != "linux" || env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "little" || !matches!(arch.as_str(), "x86_64" | "aarch64") { fs::write(output, []).unwrap(); return; // Protected activation explicitly refuses unavailable artifacts. } let compiler = env::var("ARCHY_RUNTIME_PROXY_CC").unwrap_or_else(|_| { if env::var("HOST").unwrap() == env::var("TARGET").unwrap() { "/usr/bin/cc".into() } else if arch == "aarch64" { "/usr/bin/aarch64-linux-gnu-gcc".into() } else { "/usr/bin/x86_64-linux-gnu-gcc".into() } }); assert!( std::path::Path::new(&compiler).is_absolute(), "ARCHY_RUNTIME_PROXY_CC must be an absolute executable path" ); println!("cargo:rerun-if-changed={compiler}"); let source = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()).join("../runtime-proxy.c"); let status = Command::new(&compiler) .env_clear() .env("PATH", "/usr/bin:/bin") .env("LC_ALL", "C") .args([ "-std=c11", "-O2", "-static-pie", "-fstack-protector-strong", "-D_FORTIFY_SOURCE=3", "-Wl,-z,relro,-z,now", "-Wall", "-Wextra", "-Werror", "-fno-ident", ]) .arg(source) .arg("-o") .arg(&output) .status() .expect("compile static runtime proxy"); assert!(status.success(), "static runtime proxy compilation failed"); let bytes = fs::read(output).unwrap(); assert!( bytes.len() >= 64 && bytes.len() <= 8 * 1024 * 1024 && &bytes[..4] == b"\x7fELF" && bytes[4] == 2 && bytes[5] == 1, "runtime proxy must be a bounded little-endian ELF64 executable" ); let machine = u16::from_le_bytes(bytes[18..20].try_into().unwrap()); assert_eq!( machine, if arch == "x86_64" { 62 } else { 183 }, "runtime proxy target differs from backend" ); let offset = usize::try_from(u64::from_le_bytes(bytes[32..40].try_into().unwrap())).unwrap(); let size = u16::from_le_bytes(bytes[54..56].try_into().unwrap()) as usize; let count = u16::from_le_bytes(bytes[56..58].try_into().unwrap()) as usize; assert!( size == 56 && count > 0 && count <= 128 && offset.checked_add(size * count).unwrap() <= bytes.len() ); for index in 0..count { assert_ne!( u32::from_le_bytes( bytes[offset + index * size..offset + index * size + 4] .try_into() .unwrap() ), 3, "runtime proxy must have no injectable ELF interpreter" ); } }