How to call function from Rust naked function? - rust

just started learning Rust. How do you manage a function call from a Rust naked function? Normally,
pub extern "C" fn bar() {
hprintln!("Function Call!");
}
pub extern "C" fn foo() {
unsafe {
asm!(
"blx {}",
...
in(reg) bar as u32,
);
}
}
But foo() being a naked call, I cannot use a register to pass values. There aren't much documentation on this feature and only thing I figured is that I can use constant and symbol, but I'm not sure how they are used. Any useful documentation on this feature or usage guideline would be greatly appreciated! Thanks.

Figured out a quick fix: function parameters are stored in registers (r0-r3).
pub extern "C" fn bar() {
hprintln!("Function Call!");
}
#[naked]
pub extern "C" fn foo(ft: u32) {
unsafe {
asm!(
"blx r0", // ft is stored in r0
);
}
}
// somewhere
foo(bar as u32);
I believe there are different ways to solve this using constant and symbol though. Would appreciate any input.

Related

How to reuse Tokio runtime in Rust FFI library

I want to write a FFI wrapper for sn_api library, which contains async functions. It will be used in single-threaded non-async code written in Red.
I found, that the easy way is to use Runtime::new().unwrap().block_on(...) in every exported function, although it involves a lot of creating new Tokio runtimes and seem to be too heavy to be run on every call:
use std::os::raw::c_char;
use std::ffi::{CString, CStr};
use sn_api::{BootstrapConfig, Safe};
use tokio::runtime::Runtime;
#[no_mangle]
pub extern "C" _safe_connect(ptr: *const Safe, bootstrap_contact: *const c_char) {
assert!(!ptr.is_null());
let _safe = unsafe {
&*ptr
};
let bootstrap_contact = unsafe {
CStr::from_ptr(bootstrap_contact)
}
let mut bootstrap_contacts = BootstrapConfig::default();
bootstrap_contacts.insert(bootstrap_contact.parse().expect("Invalid bootstrap address"));
// how to reuse the Runtime in other functions?
Runtime::new().unwrap().block_on(_safe.connect(None, None, Some(bootstrap_contacts)));
}
Is it possible to run all async functions on a common Runtime? I imagine it would require creating some singleton / global, but my library is compiled with crate-type = ["cdylib"], which seems not a good place for globals. What would be the best approach?
I've decided for an approach, where I create a Tokio Runtime, and then pass it to every FFI function call containing async code:
use std::os::raw::c_char;
use std::ffi::{CString, CStr};
use sn_api::{BootstrapConfig, Safe};
use tokio::runtime::Runtime;
#[no_mangle]
pub extern "C" fn init_runtime() -> *mut Runtime {
Box::into_raw(Box::new(Runtime::new().unwrap()))
}
#[no_mangle]
pub extern "C" _safe_connect(rt_ptr: *mut Runtime, safe_ptr: *mut Safe, bootstrap_contact: *const c_char) {
assert!(!safe_ptr.is_null());
assert!(!rt_ptr.is_null());
let bootstrap_contact = unsafe {
CStr::from_ptr(bootstrap_contact)
}
let mut bootstrap_contacts = BootstrapConfig::default();
bootstrap_contacts.insert(bootstrap_contact.parse().expect("Invalid bootstrap address"));
unsafe {
let _safe = &mut *safe_ptr;
let rt = &mut *rt_ptr;
rt.block_on(_safe.connect(None, None, Some(bootstrap_contacts))).unwrap();
}
}
I faced the same issue. Here is my cut: export-tokio-to-lib.
plugin.rs:
use async_ffi::{FfiFuture, FutureExt};
use tokio::runtime::Handle;
/// # Safety
#[no_mangle]
pub unsafe extern "C" fn test(arg: f32, handle: *const Handle) -> FfiFuture<safer_ffi::String> {
let handle = &*handle;
async move {
let _enter = handle.enter();
tokio::time::sleep(std::time::Duration::from_secs_f32(arg)).await;
format!("slept {arg} secs").into()
}
.into_ffi()
}
Try this.
From this:
#[tokio::main]
async fn main() {
println!("hello");
}
Transformed into:
fn main() {
let mut rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
println!("hello");
})
}
Reference: https://tokio.rs/tokio/tutorial/hello-tokio#async-main-function

How to "extern" a function in multiple modules with the same name?

I have a lib project with multiple modules called one and two, in separate files. Each module has a function called run:
mod one {
pub fn run() {
println!("One");
}
}
mod two {
pub fn run() {
println!("Two");
}
}
fn main() {
one::run();
two::run();
}
Playground
I would like to compile each of these files/functions to WebAssembly and then be able to load them and call the function run().
I believe I have to add the #[no_mangle] directive and mark them as extern "C" functions. When I do that, then there is a name clash on the run function, despite the module structure.
This is the modified version that won't compile:
mod one {
#[no_mangle]
pub extern "C" fn run() {
println!("One");
}
}
mod two {
#[no_mangle]
pub extern "C" fn run() {
println!("Two");
}
}
fn main() {
one::run();
two::run();
}
Playground
Is there a way to have multiple modules in a project, each with a function with the same name, such that I can compile the files with the function to WebAssembly, preserving the function name?
No, you cannot give multiple things the same name in a global namespace. That's kind of the definition of what a name and a namespace is. You will need to export them as two different names.
I prefer to have a single location that exports things so it's easier to see and prevent clashes. Additionally, your symbols should be unique among all libraries that will ever be linked with your library. That's why most high-quality C projects use the library name in every single public method.
mod one {
pub fn run() {
println!("One");
}
}
mod two {
pub fn run() {
println!("Two");
}
}
#[no_mangle]
pub extern "C" fn mylib_one_run() {
one::run()
}
#[no_mangle]
pub extern "C" fn mylib_two_run() {
two::run()
}
fn main() {
one::run();
two::run();
}
See also:
How do I apply a macro attribute to a function defined in a separate module?

Rust not creating function in lib extern FFI

I have many Rust functions working perfectly across Ruby FFI. But following directions from two different sites for creating a free_array method is not making the method available in the linked library.
This example is the working example of freeing a String returned from Ruby.
use libc::c_char;
use std::ffi::CString;
#[no_mangle]
pub extern "C" fn free_string(s: *mut c_char) {
unsafe {
if s.is_null() { return }
CString::from_raw(s)
};
}
And here are two attempts at implementing a way to free the memory of an Array.
use std::mem::transmute;
use ruby_array::RubyArray;
#[no_mangle]
pub extern "C" fn free_array(ra: *mut RubyArray) {
let _ra: Box<RubyArray> = unsafe{ transmute(ra) };
}
// OR
#[no_mangle]
pub extern "C" fn free_array(ptr: *mut RubyArray) {
if ptr.is_null() { return }
unsafe { Box::from_raw(ptr); }
}
This results in an error:
Function 'free_array' not found in [/libfaster_path.so] (FFI::NotFoundError)
Here's the Struct I'm using and which gets created perfectly in to Ruby from Rust.
use libc;
use std::mem;
#[repr(C)]
pub struct RubyArray {
len: libc::size_t,
data: *const libc::c_void,
}
impl RubyArray {
#[allow(dead_code)]
pub fn from_vec<T>(vec: Vec<T>) -> RubyArray {
let array = RubyArray {
data: vec.as_ptr() as *const libc::c_void,
len: vec.len() as libc::size_t
};
mem::forget(vec);
array
}
}
But that's not relevant as it's not the issue. The issue is the method is not being made available in the library output for FFI to read from. What's wrong with this? Rust is happy and I've written many other methods in similar manner that work. What makes this not found in the .so file?
The file is included in the main src/lib.rs with pub mod so there's nothing wrong there. It's the same as the other working methods.
I'll be posting a blog with much fuller implementation details later and I'll add a link to the comment section below for those who are interested.
Minor Update
I'm pretty sure this is an issue with Rust. I've used both Ruby's Fiddle and FFI to verify that this method couldn't be accessed where as other methods could be by both.
I grepped the binary and found the text showing the free_array method in the binary but apparently that's not compiled correctly to be read by FFI.
The information I provided was not enough to debug the issue. The real problem was I had changed from building source from release to debug and had not updated the FFI linked library folder to reflect that. So the code kept pointing at and old lib.

How to wrap a call to a FFI function that uses VarArgs in Rust?

mexPrintf, just like printf, accepts a varargs list of arguments, but I don't know what the best way to wrap this is in Rust. There is a RFC for variadic generics, but what can we do today?
In this example, I want to print of the number of inputs and outputs, but the wrapped function just prints garbage. Any idea how to fix this?
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate mex_sys;
use mex_sys::mxArray;
use std::ffi::CString;
use std::os::raw::c_int;
use std::os::raw::c_void;
type VarArgs = *mut c_void;
// attempt to wrap mex_sys::mexPrintf
fn mexPrintf(fmt: &str, args: VarArgs) {
let cs = CString::new(fmt).unwrap();
unsafe {
mex_sys::mexPrintf(cs.as_ptr(), args);
}
}
#[no_mangle]
pub extern "system" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *mut *mut mxArray,
) {
let hw = CString::new("hello world\n").unwrap();
unsafe {
mex_sys::mexPrintf(hw.as_ptr());
}
let inout = CString::new("%d inputs and %d outputs\n").unwrap();
unsafe {
mex_sys::mexPrintf(inout.as_ptr(), nrhs, nlhs);
}
mexPrintf("hello world wrapped\n", std::ptr::null_mut());
let n = Box::new(nrhs);
let p = Box::into_raw(n);
mexPrintf("inputs %d\n", p as VarArgs);
let mut v = vec![3];
mexPrintf("vec %d\n", v.as_mut_ptr() as VarArgs);
}
Contrary to popular belief, it is possible to call variadic / vararg functions that were defined in C. That doesn't mean that doing so is very easy, and it's definitely even easier to do something bad because there are even fewer types for the compiler to check your work with.
Here's an example of calling printf. I've hard-coded just about everything:
extern crate libc;
fn my_thing() {
unsafe {
libc::printf(b"Hello, %s (%d)\0".as_ptr() as *const i8, b"world\0".as_ptr(), 42i32);
}
}
fn main() {
my_thing()
}
Note that I have to very explicitly make sure my format string and arguments are all the right types and the strings are NUL-terminated.
Normally, you'll use tools like CString:
extern crate libc;
use std::ffi::CString;
fn my_thing(name: &str, number: i32) {
let fmt = CString::new("Hello, %s (%d)").expect("Invalid format string");
let name = CString::new(name).expect("Invalid name");
unsafe {
libc::printf(fmt.as_ptr(), name.as_ptr(), number);
}
}
fn main() {
my_thing("world", 42)
}
The Rust compiler test suite also has an example of calling a variadic function.
A word of warning specifically for printf-like functions: C compiler-writers realized that people screw up this particular type of variadic function call all the time. To help combat that, they've encoded special logic that parses the format string and attempts to check the argument types against the types the format string expect. The Rust compiler will not check your C-style format strings for you!
I had confused a "variable list of arguments" with a va_list. I'm going to avoid both if I can and in this situation, I'm just going to do the string formatting in Rust before passing it to interop. Here is what worked for me in this case:
#![allow(non_snake_case)]
#![allow(unused_variables)]
extern crate mex_sys;
use mex_sys::mxArray;
use std::ffi::CString;
use std::os::raw::c_int;
// attempt to wrap mex_sys::mexPrintf
fn mexPrintf(text: &str) {
let cs = CString::new(text).expect("Invalid text");
unsafe {
mex_sys::mexPrintf(cs.as_ptr());
}
}
#[no_mangle]
pub extern "C" fn mexFunction(
nlhs: c_int,
plhs: *mut *mut mxArray,
nrhs: c_int,
prhs: *mut *mut mxArray,
) {
mexPrintf(&format!("{} inputs and {} outputs\n", nrhs, nlhs));
}

How do I obtain the address of a function?

How do I obtain a function address in Rust? What does '&somefunction' exactly mean?
What addresses do I get doing
std::mem::transmute::<_, u32>(function)
or
std::mem::transmute::<_, u32>(&function)
(on 32-bit system, of course)?
What does
&function as *const _ as *const c_void
give?
If I just wanted to know the address of a function, I'd probably just print it out:
fn moo() {}
fn main() {
println!("{:p}", moo as *const ());
}
However, I can't think of a useful reason to want to do this. Usually, there's something you want to do with the function. In those cases, you might as well just pass the function directly, no need to deal with the address:
fn moo() {}
fn do_moo(f: fn()) {
f()
}
fn main() {
do_moo(moo);
}
I'm less sure about this, but I think that std::mem::transmute::<_, u32>(&function) would just create a local variable that points to function and then gets the reference to that variable. This would match how this code works:
fn main() {
let a = &42;
}
I need not to work with them in Rust, I need an address because I have some FFI that takes an address of the symbol in the current process
You can still just pass the function as-is to the extern functions that will use the callback:
extern {
fn a_thing_that_does_a_callback(callback: extern fn(u8) -> bool);
}
extern fn zero(a: u8) -> bool { a == 0 }
fn main() {
unsafe { a_thing_that_does_a_callback(zero); }
}
The answer by #Shepmaster gives answer to this question (though giving also other not relevant but may be useful for somebody information). I summarize it here.
Obtaining address is easy, just
funct as *const ()
Reference to a function seems to create a local variable just like with
let a = &42;

Resources