【问题标题】:Invoke libc::c_void-Pointer as function in Rust with parameters [duplicate]使用参数调用 libc::c_void-Pointer 作为 Rust 中的函数 [重复]
【发布时间】:2019-07-17 19:22:14
【问题描述】:

你好互联网的人们,

我正在努力调用一个存储在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;
}

去锈。

#[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 / Rust with libc。我尝试了很多 unsafe{},使用 as 进行强制转换,但我总是遇到以下问题:

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

Q1:如何调用存储在real_malloc中的void-Pointer后面的函数?

Q2:我的 Rust-String 到 C-String 转换这种方式可行吗?

【问题讨论】:

  • 我认为在尝试做 ffi 之前应该优先学习基础知识,如何从函数中返回一些东西。
  • @Stargateur 是的,确实!请看看我自己对这篇文章的回答。我找到了你提到的帖子,它对我有帮助!还是谢谢!
  • 我找到它是因为你找到了它,正如你自己所说,这解决了你的问题,所以它很可能是一个很好的重复候选者。只是将这个问题“标记”为接近,因为存在一个更通用的答案,如果未来的读者阅读您的问题,他们可以直接阅读。
  • 好的!不知道它是否真的是重复的,因为这里的流行词是 void-Pointer。我可能不是唯一一个搜索这个而不是“原始地址”的人——你怎么看?
  • 您的问题不会被删除,您的答案也不会被删除。只是我们阻止未来的人在这里写答案,而是鼓励人们在副本上写答案(如果需要)。 “重复的问题不一定是坏事;对同一问题的不同描述有助于未来的访问者找到他们正在寻找的答案。”见meta.stackexchange.com/questions/10841/…

标签: rust


【解决方案1】:

我想通了!也许有更好的方法,但它确实有效。

诀窍是使用std::mem::transmute 将 void-Pointer “转换”为 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(在我google了很多之后,我发现了transmute的诀窍!)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-14
    • 2021-04-23
    • 1970-01-01
    • 1970-01-01
    • 2020-11-09
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    相关资源
    最近更新 更多