从Rust调用一个原始地址

Isa*_*ods 5 function-pointers osdev rust

我在Rust中编写一个操作系统,需要直接调用我正在计算的虚拟地址(类型u32).我希望这相对简单:

let code = virtual_address as (extern "C" fn ());
(code)();
Run Code Online (Sandbox Code Playgroud)

然而,这抱怨演员阵容是非原始的.它建议我使用这个From特性,但我不知道这有多大帮助(尽管我对Rust来说相对较新,所以可能会遗漏一些东西).

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
Run Code Online (Sandbox Code Playgroud)

注意:我掌握了一切libcore,但没有移植std,所以不能依赖任何不是no_std的东西

Luk*_*odt 7

_ as f-ptr不允许使用该类型的强制转换(请参阅关于强制转换的Rustonomicon章节).所以,据我所知,转换为函数指针类型的唯一方法是使用所有强大的武器mem::transmute().

但在我们使用之前transmute(),我们必须将输入引入正确的内存布局.我们通过转换为*const ()(void指针)来做到这一点.之后我们可以transmute()用来获得我们想要的东西:

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

但是,有一些注意事项:

  • 如果你,未来的读者,想用这个做简单的FFI事情:请花点时间再考虑一下.很难自己计算函数指针.
  • 通常extern "C"函数具有类型unsafe extern "C" fn().这意味着这些功能不安全.您应该添加unsafe到您的功能.