问题
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
NOTE: 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
回答1:
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)();
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 typeunsafe extern "C" fn()
. This means that those functions are unsafe to call. You should probably add theunsafe
to your function.
来源:https://stackoverflow.com/questions/46134477/call-a-raw-address-from-rust