使用参数调用libc :: c_void-Pointer作为Rust中的函数

时间:2019-07-17 19:22:14

标签: rust

互联网的大家好,

我正在努力调用存储在libc::c_void-Pointer中的函数。我不能告诉Rust指针是可调用的,我也不知道该怎么做。

我想翻译此C ++代码

void * malloc(size_t size) {
    static void *(*real_malloc)(size_t) = nullptr;
    if (real_malloc == nullptr) {
        real_malloc = reinterpret_cast<void *(*)(size_t)> (dlsym(RTLD_NEXT, "malloc"));
    }
    // do some logging stuff
    void * ptr = real_malloc(size);
    return ptr;
}

到Rust。

#[no_mangle]
pub extern fn malloc(bytes: usize) {
    let c_string = "malloc\0".as_mut_ptr() as *mut i8; // char array for libc
    let real_malloc: *mut libc::c_void = libc::dlsym(libc::RTLD_NEXT, c_string);
    return real_malloc(bytes);
}

到目前为止,这是我在互联网上搜索并尝试1小时后的进步。我是Rust的新手,还不熟悉Rust / FFI / libc的Rust。我对不安全的{}进行了很多尝试,对as进行了强制转换,但始终遇到以下问题:

return real_malloc(bytes);
       ^^^^^^^^^^^^^^^^^^ expected (), found *-ptr

问题1:我如何调用存储在real_malloc中的void指针后面的函数?

第二季度:这样,我的Rust-String到C-String转换可行吗?

1 个答案:

答案 0 :(得分:0)

我知道了!也许有更好的方法,但是它行得通。

诀窍是用std::mem::transmute将void指针“投射”到c-function-Type,因为它不能与as一起使用

type LibCMallocT = fn(usize) -> *mut libc::c_void;

// C-Style string for symbol-name
let c_string = "malloc\0".as_ptr() as *mut i8; // char array for libc
// Void-Pointer to address of symbol
let real_malloc_addr: *mut libc::c_void = unsafe {libc::dlsym(libc::RTLD_NEXT, c_string)};
// transmute: "Reinterprets the bits of a value of one type as another type"
// Transform void-pointer-type to callable C-Function
let real_malloc: LibCMallocT = unsafe { std::mem::transmute(real_malloc_addr) }

构建共享库时,可以验证其是否像这样工作: LD_PRELOAD=./target/debug/libmalloc_log_lib.so some-binary


我的完整代码:

extern crate libc;

use std::io::Write;

const MSG: &str = "HELLO WORLD\n";

type LibCMallocT = fn(usize) -> *mut libc::c_void;

#[no_mangle] // then "malloc" is the symbol name so that ELF-Files can find it (if this lib is preloaded)
pub extern fn malloc(bytes: usize) -> *mut libc::c_void {
    /// Disable logging aka return immediately the pointer from the real malloc (libc malloc)
    static mut RETURN_IMMEDIATELY: bool = false;

    // C-Style string for symbol-name
    let c_string = "malloc\0".as_ptr() as *mut i8; // char array for libc
    // Void-Pointer to address of symbol
    let real_malloc_addr: *mut libc::c_void = unsafe {libc::dlsym(libc::RTLD_NEXT, c_string)};
    // transmute: "Reinterprets the bits of a value of one type as another type"
    // Transform void-pointer-type to callable C-Function
    let real_malloc: LibCMallocT = unsafe { std::mem::transmute(real_malloc_addr) };

    unsafe {
        if !RETURN_IMMEDIATELY {
            // let's do logging and other stuff that potentially
            // needs malloc() itself

            // This Variable prevent infinite loops because 'std::io::stdout().write_all'
            // also uses malloc itself

            // TODO: Do proper synchronisazion
            //  (lock whole method? thread_local variable?)
            RETURN_IMMEDIATELY = true;
            match std::io::stdout().write_all(MSG.as_bytes()) {
                _ => ()
            };
            RETURN_IMMEDIATELY = false
        }
    }

    (real_malloc)(bytes)
}

PS:感谢https://stackoverflow.com/a/46134764/2891595(在我搜索了很多之后,我发现了transmute的窍门!)