Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use `dlsym()` in Rust [duplicate]

I am writing an OS in Rust and need to directly call into a virtual address that I'm calculating (of type u32). I expected this to be relatively simple:

let code = virtual_address as (extern "C" fn ());
(code)();

However, this complains that the cast is non-primitive. It suggests I use the From trait, but I don't see how this could help (although I am relatively new to Rust and so could be missing something).

error[E0605]: non-primitive cast: `u32` as `extern "C" fn()`
 --> src/main.rs:3:16
  |
3 |     let code = virtual_address as (extern "C" fn ());
  |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait

I have everything in libcore at my disposal, but haven't ported std and so can't rely on anything that isn't no_std

like image 712
Isaac Woods Avatar asked Dec 06 '25 13:12

Isaac Woods


1 Answers

Casts of the type _ as f-ptr are not allowed (see the Rustonomicon chapter on casts). So, as far as I can tell, the only way to cast to function pointer types is to use the all mighty weapon mem::transmute().

But before we can use transmute(), we have to bring our input into the right memory layout. We do this by casting to *const () (a void pointer). Afterwards we can use transmute() to get what we want:

let ptr = virtual_address as *const ();
let code: extern "C" fn() = unsafe { std::mem::transmute(ptr) };
(code)();

If you find yourself doing this frequently, various kinds of macros can remove the boilerplate. One possibility:

macro_rules! example {
    ($address:expr, $t:ty) => {
        std::mem::transmute::<*const (), $t>($address as _)
    };
}
let f = unsafe { example!(virtual_address, extern "C" fn()) };
f(); 

However, a few notes on this:

  • If you, future reader, want to use this to do simple FFI things: please take a moment to think about it again. Calculating function pointers yourself is rarely necessary.
  • Usually extern "C" functions have the type unsafe extern "C" fn(). This means that those functions are unsafe to call. You should probably add the unsafe to your function.
like image 156
Lukas Kalbertodt Avatar answered Dec 08 '25 21:12

Lukas Kalbertodt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!