2017-09-09 5 views
1

J'écris un OS dans Rust et j'ai besoin d'appeler directement une adresse virtuelle que je calcule (de type u32). Je m'attendais à ce que ce soit relativement simple:Appeler une adresse brute de Rust

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

Cependant, cela se plaint que la distribution est non-primitive. Il suggère que j'utilise le trait From, mais je ne vois pas comment cela pourrait aider (bien que je sois relativement nouveau à Rust et que je puisse manquer quelque chose).

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: J'ai tout libcore à ma disposition, mais ne l'ai pas porté std et ne peut donc pas compter sur quoi que ce soit qui ne no_std

Répondre

3

Casts du type _ as f-ptr ne sont pas autorisés (voir the Rustonomicon chapter on casts). Donc, autant que je sache, la seule façon de lancer des types de pointeurs de fonction est d'utiliser l'arme toute puissante mem::transmute(). Mais avant que nous puissions utiliser transmute(), nous devons apporter notre contribution dans la bonne disposition de la mémoire. Nous faisons cela en castant à *const() (un pointeur de vide). nous pouvons par la suite utiliser transmute() pour obtenir ce que nous voulons:

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

Cependant, quelques notes sur ce point:

  • Si vous, futur lecteur, voulez l'utiliser pour faire des choses IFF simples : s'il vous plaît prenez un moment pour y penser à nouveau. Le calcul des pointeurs de fonction est rarement nécessaire.
  • Généralement les fonctions extern "C" ont le type unsafe extern "C" fn(). Cela signifie que ces fonctions sont dangereuses à appeler. Vous devriez probablement ajouter le unsafe à votre fonction.
+0

S'il vous plaît noter que je ne suis absolument pas un expert sur les choses dangereuses! Si quelqu'un sait mieux, s'il vous plaît faites le moi savoir; alors je peux éditer ou supprimer ma réponse! –

+0

Rust ne fait rien de fantaisie ici. 'fn()' est un pointeur de fonction simple. Tant qu'il y a une fonction dans 'virtual_address', les conventions d'appel et les signatures correspondent, c'est OK de lancer la distribution et d'appeler la fonction. – red75prime

+0

Génial, je vais devoir faire un peu plus d'installation pour voir si cela fonctionne réellement, mais ça compile! Merci beaucoup @LukasKalbertodt. –