Rust中如何初始化供gen_func赋值的extern fn函数指针变量
问题描述
我实现了名为gen_func()的函数,该函数接收&mut extern fn(i64) -> i64类型的可变引用作为入参,内部基于GNU Lightning代码生成库生成机器码后,将得到的可执行函数指针写入该引用指向的位置。
当前构造传入参数时遇到问题:不清楚应当如何声明、初始化对应类型的函数变量,才能合法将其可变引用传入gen_func()完成赋值,相关代码片段如下:
let func = [此处应当填写什么代码?]; gen_func(&mut func);
补充说明:我完全拥有gen_func()的实现控制权,整体开发目标是实现一套可动态生成并直接执行目标函数的代码生成逻辑。
实现方法
直接声明对应类型的可变变量,用同签名的桩函数完成初始化即可,代码完全符合Rust引用规则,可直接运行:
// 定义签名完全匹配的桩函数,仅作初始化占位使用 extern "C" fn dummy_stub(_: i64) -> i64 { unreachable!("函数指针未完成动态生成,禁止调用桩函数") } let mut func: extern "C" fn(i64) -> i64 = dummy_stub; gen_func(&mut func); // 写入完成后可直接调用生成的函数 let result = func(42);
注意事项
- 必须明确标注函数指针的ABI为
extern "C",和GNU Lightning默认使用的C语言调用约定对齐,避免因调用约定不匹配导致参数传递错误、栈损坏等崩溃问题。 - 禁止使用
std::mem::zeroed()初始化函数指针,零值函数指针属于Rust中定义的无效值,会触发未定义行为,即使后续会立刻覆写该值也存在被编译器错误优化的风险。 - 如果不想保留无实际作用的桩函数,可以调整
gen_func的入参类型为裸指针*mut extern "C" fn(i64) -> i64,配合std::mem::MaybeUninit使用,实现零开销初始化,示例代码如下:
这种写法不需要额外的桩函数,逻辑更贴合动态代码生成的场景,只要保证use std::mem::MaybeUninit; let mut func = MaybeUninit::<extern "C" fn(i64) -> i64>::uninit(); gen_func(func.as_mut_ptr()); // 写入完成后再拿到可用的函数指针 let func = unsafe { func.assume_init() }; let result = func(42);gen_func内部一定会完成指针写入,就不会有内存安全问题。
内容的提问来源于stack exchange,提问作者slackers
相关产品推荐
相关产品推荐

