How to call C function in Rust - rust

I'm a C programmer and I'm trying to call Rust function in my application and the rust function also need call C functions which exist at my application.
I know that if I want call C function in Rust I have to do like this
#[link(name = "mylib")]
extern "C" {
pub fn c_function();
}
But the c_function doesn't exist in any lib but only in my application env now.
For example:
My C code is
void c_function()
{
return 1;
}
void main()
{
rust_function();
}
My Rust code is(cargo new --lib myrustlib)
pub unsafe extern "C" fn rust_function() {
//If I want to call c_function which is in C world here, How could I do this?
//I have tried using extern "C" {pub fn c_function();} but faild.
//And an error is outputted like this "undefined reference to `c_function'"
}

You're on the right track. You can auto-generate C header from the Rust program with cbindgen, and the other way, Rust bindings with bindgen.
Add crate-type = ["lib", "staticlib", "cdylib"] to Cargo.toml to generate .a and .so/.dylib/.dll versions of the Rust library that you can link with the C program.

Related

Rust ffi include dynamic library in cross platform fashion

I would like to include a dynamic C library in Rust with FFI.
The library is actually also build with Rust, but exposes a C interface, so that it can be used from other languages, too. When I build the library (type: cdylib) with cargo I get a .dylib on MacOS and a .dll as well as a .dll.lib file on windows. These libraries also get different names, derived from the project name (libmy_lib.dylib on MacOS and my_lib.dll as well as my_lib.dll.lib on Windows).
I would like to reference these files in a cross-platform way. Because currently I have to use
#[link(name = "my_lib.dll", kind = "dylib")]
on windows, whereas on MacOS I need to use
#[link(name = "my_lib", kind = "dylib")]
I have already tried to rename the my_lib.dll.lib to my_lib.lib, but I still get a Linker Error, saying
LINK : fatal error LNK1181: cannot open input file 'my_lib.lib'
How can I reference the files, so that I can use my code for Mac and Windows? If thats only possible with cfg_attr tags I would also accept that. Ideally I would also like to get rid of the .lib file for windows if possible.
You could use crate libloading
Example:
let lib = unsafe {
#[cfg(unix)]
let path = "mylib.so";
#[cfg(windows)]
let path = "mylib.dll";
libloading::Library::new(path).expect("Failed to load library")
};
let func: libloading::Symbol<unsafe extern fn() -> u32> = unsafe {
lib.get(b"my_func").expect("Failed to load function `my_func`")
};
// Can call func later while `lib` in scope
For what it's worth, I found a temporary solution for this now.
I used this pattern:
#[cfg(windows)]
#[link(name = "my_lib.dll", kind = "dylib")]
extern {
// Reference the exported functions
}
#[cfg(unix)]
#[link(name = "my_lib", kind = "dylib")]
extern {
// Reference the exported functions
}
I don't like it that much, because I had to define the very same extern{} block twice, but it works and I could also extend this pattern to for example use #[cfg(target_os = "macos")] if needed...
EDIT: Thanks to #Angelicos Phosphoros I improved the code a bit by using a macro like so:
/// Import native functions with the Rust FFI
macro_rules! import_native_functions {
() => {
// Reference the exported functions
};
}
#[cfg(windows)]
#[link(name = "my_lib.dll", kind = "dylib")]
extern {
import_native_functions!();
}
#[cfg(unix)]
#[link(name = "my_lib", kind = "dylib")]
extern {
import_native_functions!();
}

Calling a library function with rust-abi

I have a couple of crates X and Y. The first ones manages low-level stuff and defines an entry point. Then it should transfer control to the Y, which do high-level logic. I would like to explicitly declare Y's function in X and call it (so the linker connects these while building Y-crate).
I know Rust has non-stable ABI, but I use both of these crates in one workspace with the same compiler.
I tried with the following example, but the linker cannot find real_main (undefined reference ...):
// X's main.rs
#[link(name = "y_lib_name", link = "static")]
extern "Rust" {
fn real_main();
}
fn main() {
// is it possible to avoid unsafe here, btw?
unsafe { real_main() }
}
// Y's lib.rs
pub fn real_main() { .. }
Though the symbol exists:
$ nm target/debug/deps/liby_lib_name-8ade2b95fe4044c6.rlib | rg real_main
nm: lib.rmeta: file format not recognized
0000000000000000 T _ZN8y_lib_name9real_main17h8664760a5d2676beE
I guess my issue can be resolved via macro in X like the following:
// in X
#[macro_export]
macro_rules define_ep! {
($fn:expr) => {{ fn main() { $fn(); } }}
}
// in Y
fn f() {}
X::define_ep!(f);
but I would prefer the linker-backed way because:
if you forgot linker just give you an error;
(not sure) linker gives an error if symbols appears more than once.

How do I get the return address of a function?

I am writing a Rust library containing an implementation of the callbacks for LLVM SanitizerCoverage. These callbacks can be used to trace the execution of an instrumented program.
A common way to produce a trace is to print the address of each executed basic block. However, in order to do that, it is necessary to retrieve the address of the call instruction that invoked the callback. The C++ examples provided by LLVM rely on the compiler intrinsic __builtin_return_address(0) in order to obtain this information.
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
if (!*guard) return;
void *PC = __builtin_return_address(0);
printf("guard: %p %x PC %p\n", guard, *guard, PC);
}
I am trying to reproduce the same function in Rust but, apparently, there is no equivalent to __builtin_return_address. The only reference I found is from an old version of Rust, but the function described is not available anymore. The function is the following:
pub unsafe extern "rust-intrinsic" fn return_address() -> *const u8
My current hacky solution involves having a C file in my crate that contains the following function:
void* get_return_address() {
return __builtin_return_address(1);
}
If I call it from a Rust function, I am able to obtain the return address of the Rust function itself. This solution, however, requires the compilation of my Rust code with -C force-frame-pointers=yes for it to work, since the C compiler intrinsic relies on the presence of frame pointers.
Concluding, is there a more straightforward way of getting the return address of the current function in Rust?
edit: The removal of the return_address intrinsic is discussed in this GitHub issue.
edit 2: Further testing showed that the backtrace crate is able to correctly extract the return address of the current function, thus avoiding the hack I described before. Credit goes to this tweet.
The problem with this solution is the overhead that is generated creating a full backtrace when only the return address of the current function is needed. In addition, the crate is using C libraries to extract the backtrace; this looks like something that should be done in pure Rust.
edit 3: The compiler intrinsic __builtin_return_address(0) generates a call to the LLVM intrinsic llvm.returnaddress. The corresponding documentation can be found here.
I could not find any official documentation about this, but found out by asking in the rust-lang repository: You can link against LLVM intrinsics, like llvm.returnaddress, with only a few lines of code:
extern {
#[link_name = "llvm.returnaddress"]
fn return_address() -> *const u8;
}
fn foo() {
println!("I was called by {:X}", return_address());
}
The LLVM intrinsic llvm.addressofreturnaddress might also be interesting.
As of 2022 Maurice's answer doesn't work as-is and requires an additional argument.
#![feature(link_llvm_intrinsics)]
extern {
#[link_name = "llvm.returnaddress"]
fn return_address(a: i32) -> *const u8;
}
macro_rules! caller_address {
() => {
unsafe { return_address(0) }
};
}
fn print_caller() {
println!("caller: {:p}", caller_address!());
}
fn main() {
println!("main address: {:p}", main as *const ());
print_caller();
}
Output:
main address: 0x56261a13bb50
caller: 0x56261a13bbaf
Playground link;

Undefined reference to main when using Real-Time For the Masses

I'm trying to write a multi-threaded bare-metal application for the STM32F4Discovery using the Real-Time For the Masses (RTFM) crate. I've frankensteined together a minimal application from an example for the STM32F3Discovery board and this example:
#![deny(unsafe_code)]
#![no_main]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rtfm as rtfm;
extern crate cortex_m_semihosting;
extern crate panic_semihosting;
extern crate stm32f4;
use stm32f4::stm32f407;
use rtfm::app;
app! {
device: stm32f407,
}
fn init(_p: init::Peripherals) {
}
fn idle() -> ! {
loop {
rtfm::wfi();
}
}
I can get it to compile but linking with rust-lld fails with
= note: rust-lld: error: undefined symbol: main
I am confused because when I run cargo expand I do get a main function:
fn main() {
#![allow(path_statements)]
let init: fn(init::Peripherals) = init;
rtfm::atomic(unsafe { &mut rtfm::Threshold::new(0) },
|_t|
unsafe {
let _late_resources =
init(init::Peripherals{core:
::stm32f407::CorePeripherals::steal(),
device:
::stm32f407::Peripherals::steal(),});
});
let idle: fn() -> ! = idle;
idle();
}
I'm new to Rust (in fact I was hoping to learn the language with this project) and have no idea where the error might be located.
As you ask the compiler to not insert main, there is no main symbol in your program.
Rust uses symbol mangling so your main function doesn't have a symbol named main.
The answer depends on your contextm but generally this should do it:
#[no_mangle] // ensure that this symbol is called `main` in the output
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
}
All additional information can be found here

In Rust how can I define or import a C struct from a third party library?

The Rust FFI guide (http://static.rust-lang.org/doc/master/guide-ffi.html) nicely demonstrates how to import C functions that use standard C types that are wrapped by the Rust std::lib library, such as size_t. But how do I bring C data structures defined in third party libraries into a Rust program?
I'm working with libmemcached, which has the following function:
memcached_st* memcached_create(memcached_st *ptr)
which is typically invoked like so in a C program (to kick things off):
#include <libmemcached/memcached.h>
// ...
memcached_st *memc;
memc = memcached_create(NULL);
The memcached_st is an opaque C struct - how do I declare and use that in a Rust program? Here are my failed attempts so far:
use std::libc::*;
use ptr;
#[link(name = "memcached")]
extern {
struct memcached_st; // error: unexpected token: `struct`
memcached_st* memcached_create(memcached_st *ptr);
}
fn main() {
unsafe {
let memc = memcached_create(ptr:null());
println!("{:?}", memc);
}
}
and
use std::libc::*;
use ptr;
#[link(name = "memcached")]
extern {
// error: unexpected token: `memcached_st`
memcached_st* memcached_create(memcached_st *ptr);
}
fn main() {
unsafe {
let memc = memcached_create(ptr:null());
println!("{:?}", memc);
}
}
Using empty structure is a valid approach. You almost got it, you just don't need to put the struct definition in extern block. Also you can't use C code inside Rust sources - extern definitions have to follow standard Rust syntax.
use std::ptr;
struct memcached_st;
#[link(name = "memcached")]
extern {
fn memcached_create(ptr: *memcached_st) -> *memcached_st;
}
fn main() {
unsafe {
let memc = memcached_create(ptr::null());
println!("{:?}", memc);
}
}

Resources