在c函数指针中存储额外数据
假设有一个库函数(不能修改)接受回调(函数指针)作为其参数,该参数将在将来某个时候调用。我的问题是:有没有一种方法可以将额外的数据与函数指针一起存储,以便在调用回调时可以检索额外的数据。这个程序是用c语言编写的 例如:在c函数指针中存储额外数据,c,function-pointers,C,Function Pointers,假设有一个库函数(不能修改)接受回调(函数指针)作为其参数,该参数将在将来某个时候调用。我的问题是:有没有一种方法可以将额外的数据与函数指针一起存储,以便在调用回调时可以检索额外的数据。这个程序是用c语言编写的 例如: // callback's type, no argument typedef void (*callback_t)(); // the library function void regist_callback(callback_t cb);
// callback's type, no argument
typedef void (*callback_t)();
// the library function
void regist_callback(callback_t cb);
// store data with the function pointer
callback_t store_data(callback_t cb, int data);
// retrieve data within the callback
int retrieve_data();
void my_callback() {
int a;
a = retrieve_data();
// do something with a ...
}
int my_func(...) {
// some variables that i want to pass to my_callback
int a;
// ... regist_callback may be called multiple times
regist_callback(store_data(my_callback, a));
// ...
}
问题是因为回调\u t不接受任何参数。我的想法是每次生成一小段asm代码填充到regist_callback中,当它被调用时,它可以找到真正的回调及其数据并将其存储在堆栈(或一些未使用的寄存器)上,然后跳转到真正的回调,并在回调中找到数据
伪代码:
typedef struct {
// some asm code knows the following is the real callback
char trampoline_code[X];
callback_t real_callback;
int data;
} func_ptr_t;
callback_t store_data(callback_t cb, int data) {
// ... malloc a func_ptr_t
func_ptr_t * fpt = malloc(...);
// fill the trampoline_code, different machine and
// different calling conversion are different
// ...
fpt->real_callback = cb;
fpt->data = data;
return (callback_t)fpt;
}
int retrieve_data() {
// ... some asm code to retrive data on stack (or some register)
// and return
}
这合理吗?以前有没有针对此类问题做过任何工作?不幸的是,随着时间的推移,您可能会被禁止在越来越多的系统中执行蹦床,因为执行数据是利用安全漏洞的一种非常常见的方式 我首先向库的作者报告这个bug。每个人都应该知道不要提供没有私有数据参数的回调接口 有了这样的限制,我会再三考虑库是否可重入。我建议确保一次只能有一个未完成的调用,并将回调参数存储在全局变量中
如果您认为该库适合使用,那么您可以通过编写不同的回调蹦床来扩展它,每个回调蹦床引用自己的全局数据,并将其封装在一些管理API中。为什么不让
存储\u date()
在全局映射中存储原始函数的地址以及对a
的引用,并通过retrieve\u data()
将其检索?如果多次注册同一回调,则在调用回调时,它不知道是哪一个。是的,实际上,这种方法无法涵盖此用例。但是,您可以通过为每个同时注册的实例实现包装器来解决这个问题。或者只使用cb函数地址中一些未使用的低(甚至高)阶位来添加子索引…-8字节指针是宽的;-)好的,如果你没有被禁止执行你的结构,你的程序集蹦床只需要执行一次对你真正的处理器的调用。然后,您的处理程序可以检查调用的返回地址以找出结构的位置。您是指jmp吗?或者打个电话?哈,我想我知道怎么做;)