Initial commit

calling C trampoline works
avec
Avril 3 years ago
commit 02bcfeb3fe
Signed by: flanchan
GPG Key ID: 284488987C31F630

2
.gitignore vendored

@ -0,0 +1,2 @@
/target
Cargo.lock

@ -0,0 +1,14 @@
[package]
name = "stackalloc"
version = "0.1.0"
authors = ["Avril <flanchan@cumallover.me>"]
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"

@ -0,0 +1,8 @@
#include <stddef.h>
void _alloca_trampoline(size_t num, void (*callback)(void* restrict ptr, void* data), void* data)
{
unsigned char ptr[num];
callback(ptr, data);
}

@ -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();
}

@ -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<CallbackRaw>, 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);
}

@ -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);
}
}
Loading…
Cancel
Save