From 02bcfeb3fecd7b1630fec8740c5c7fe06379e6b4 Mon Sep 17 00:00:00 2001 From: Avril Date: Wed, 24 Mar 2021 18:12:00 +0000 Subject: [PATCH] Initial commit calling C trampoline works --- .gitignore | 2 ++ Cargo.toml | 14 ++++++++++++++ alloca_trampoline_.c | 8 ++++++++ build.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ src/ffi.rs | 21 +++++++++++++++++++++ src/lib.rs | 27 +++++++++++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 alloca_trampoline_.c create mode 100644 build.rs create mode 100644 src/ffi.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..64b6ddd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "stackalloc" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + + +[build-dependencies] +cc = "1.0" +rustc_version = "0.2" diff --git a/alloca_trampoline_.c b/alloca_trampoline_.c new file mode 100644 index 0000000..0670613 --- /dev/null +++ b/alloca_trampoline_.c @@ -0,0 +1,8 @@ +#include + +void _alloca_trampoline(size_t num, void (*callback)(void* restrict ptr, void* data), void* data) +{ + unsigned char ptr[num]; + callback(ptr, data); +} + diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..9dea064 --- /dev/null +++ b/build.rs @@ -0,0 +1,43 @@ + +extern crate rustc_version; +use rustc_version::{version, version_meta, Channel}; + +fn build_tramp() +{ + let mut builder = cc::Build::new(); + // --std=c99 -W -Wall -Werror -pedantic -O3 -flto + builder.flag("--std=c99") + .flag("--std=c99") + .flag("-W") + .flag("-Wall") + .flag("-Werror") + .flag("-pedantic") + .opt_level(3) + .flag_if_supported("-flto") + + .file("alloca_trampoline_.c") + .compile("calloca_trampoline"); +} + +fn main() { + // Assert we haven't travelled back in time + assert!(version().unwrap().major >= 1); + + // Set cfg flags depending on release channel + match version_meta().unwrap().channel { + Channel::Stable => { + println!("cargo:rustc-cfg=stable"); + } + Channel::Beta => { + println!("cargo:rustc-cfg=beta"); + } + Channel::Nightly => { + println!("cargo:rustc-cfg=nightly"); + } + Channel::Dev => { + println!("cargo:rustc-cfg=dev"); + } + } + + build_tramp(); +} diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..cd61222 --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,21 @@ +use std::ffi::c_void; + +pub type CallbackRaw = extern "C" fn (ptr: *mut c_void, data: *mut c_void)->(); + +extern "C" { + fn _alloca_trampoline(size: usize, cb: Option, data: *mut c_void); +} + +/// Call the `_alloca_trampoline` C function. +/// +/// # Safety requirements & guarantees +/// * `size` should be small enough to not overflow the stack. A size of 0 is allowed. +/// * `cb` **must** catch any unwinds. +/// * `data` can be `null`, it is passed as the 2nd argument to `cb` as-is. +/// * The first argument to `cb` is guaranteed to be a non-aliased, properly aligned, and non-null pointer with `size` read+writable memory. If `size` is 0, it may dangle. +/// * `cb` is guaranteed to be called unless allocating `size` bytes on the stack causes a stack overflow, in which case the program will terminate. +/// * The data pointed to by `ptr` is guaranteed to be popped from the stack once `cb` returns (even in the case of a `longjmp`, but `panic!()` within the callback is still undefined behaviour). +#[inline(always)] pub unsafe fn alloca_trampoline(size: usize, cb: CallbackRaw, data: *mut c_void) +{ + _alloca_trampoline(size, Some(cb), data); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4519f4a --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,27 @@ + +mod ffi; + + +#[cfg(test)] +mod tests { + #[test] + fn raw_trampoline() + { + use std::ffi::c_void; + + let mut size: usize = 100; + extern "C" fn callback(ptr: *mut c_void, data: *mut c_void) + { + let size = unsafe {&mut *(data as *mut usize)}; + println!("From callback! Size is {}", *size); + + *size = 0; + } + + unsafe { + super::ffi::alloca_trampoline(size, callback, &mut size as *mut usize as *mut _); + } + + assert_eq!(size, 0); + } +}