Создание общей библиотеки ржавчины, которая возвращает структуру указателей на функции в главной программе C - PullRequest
0 голосов
/ 01 декабря 2018

Я пытаюсь сделать привязку Rust к nbdkit без особой удачи.Мне нужно сделать файл .so, что легко.Файл .so должен иметь публичную функцию, называемую plugin_init, также легко.Однако эта функция должна возвращать указатель на C-совместимый struct, содержащий сочетание строк и указателей на функции (которые позднее будет вызывать основная программа на C).

API: https://github.com/libguestfs/nbdkit/blob/409ce4c9238a84ede6688423b20d5f706067834b/include/nbdkit-plugin.h#L53

Я придумал:

#[repr(C)]
pub struct NBDKitPlugin {
    _struct_size: uint64_t,
    _api_version: c_int,
    _thread_model: c_int,

    name: *const c_char,
    longname: Option<*const c_char>,
    version: Option<*const c_char>,
    description: Option<*const c_char>,

    load: Option<extern fn ()>,
    unload: Option<extern fn ()>,

    config: Option<extern fn ()>, // XXX
    config_complete: Option<extern fn () -> c_int>,
    config_help: Option<*const c_char>,

    open: extern fn (c_int) -> *mut c_void,
    close: Option<extern fn (*mut c_void)>,
}

и функцию plugin_init:

extern fn hello_load () {
    println! ("hello this is the load method");
}

struct MyHandle {
}

extern fn hello_open (readonly: c_int) -> *mut c_void {
    println! ("hello, this is the open method");
    let mut h = MyHandle {};
    let vp: *mut c_void = &mut h as *mut _ as *mut c_void;
    return vp;
}

#[no_mangle]
pub extern fn plugin_init () -> *const NBDKitPlugin {
    println! ("hello from the plugin");

    let plugin = Box::new (NBDKitPlugin {
        _struct_size: mem::size_of::<NBDKitPlugin>() as uint64_t,
        _api_version: 2,
        _thread_model: 3,
        name: CString::new("hello").unwrap().into_raw(),
        longname: None,
        version: None,
        description: None,
        load: Some (hello_load),
        unload: None,
        config: None,
        config_complete: None,
        config_help: Some (CString::new("my config_help here").unwrap().into_raw()),
        open: hello_open,
        close: None,
    });

    return Box::into_raw(plugin);
}

Помимо утечки памяти, это частично работает.Целые числа и строки видны из C OK.Однако указатели на функции не работают вообще.Они полностью поддельные и, кажется, занимают больше места, чем необработанный указатель, поэтому я предполагаю, что я выставляю «толстый» указатель Rust.

Кажется, что очень мало документации по этой теме, которую я могу найти.Помощь.

1 Ответ

0 голосов
/ 03 декабря 2018

В какой-то момент вы, вероятно, узнали, что ссылка (&T), заключенная в Option (Option<&T>), оптимизирована таким образом, что None кодируется как все нули, что недопустимо для ссылкии Option<&T> имеет тот же размер, что и &T.

Однако все нули являются допустимым битовым шаблоном для необработанного указателя (*const T или *mut T): он представляет нулевой указатель.Таким образом, упаковка в Option ничем не отличается от упаковки, скажем, i32 в Option: тип Option больше, так что он может хранить дискриминант.

исправьте определение структуры, вы не должны использовать Option для определения longname, version и description.

...