设想
typedef struct xyz_data {
void *myfa;
void *myfb;
} xyz_data; // Type name assumed — not specified in question
asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);
xyz_data *xyz_data_something = ...;
xyz_data_something->myfa = hooked_sys_read;
xyz_data_something->myfb = &real_sys_read;
分析
你写的不是类型安全的(所以编译器帮不了你太多),但你正在获取保存指向“真正的 sys read”函数的指针的变量的地址,而不是该指针的副本(因为的&
)。您可以将&
(and *
) 应用于函数名称,它们最终都相同:
reader->myfa = &hooked_sys_read;
reader->myfa = hooked_sys_read;
reader->myfa = *hooked_sys_read;
reader->myfa = **hooked_sys_read;
reader->myfa = ***hooked_sys_read;
reader->myfa = ****hooked_sys_read;
你不能用指向函数的指针来做到这一点。请注意,当您执行以下操作时,编译器甚至无法诊断“分配给对象指针的函数指针”问题:
xyz_data_something->myfb = &real_sys_read;
您将(函数)指针变量的地址分配给 a void *
,因此您将对象指针分配给 void 指针,这是合法的 - 但不正确。
合成
您应该具有以下两种函数类型 typedef 之一:
typedef ssize_t ReadFunction(unsigned int fd, char __user *data, size_t size);
typedef ssize_t (*ReadPointer)(unsigned int fd, char __user *data, size_t size);
那么你的结构可以是:
typedef struct xyz_data
{
ReadFunction *myfa;
ReadFunction *myfb;
} xyz_data;
或者:
typedef struct xyz_data
{
ReadPointer myfa;
ReadPointer myfb;
} xyz_data;
给定一个结构指针:
xyz_data *reader = ...;
以下分配将编译干净并正常工作(对于两种结构类型):
reader->myfa = hooked_sys_read;
reader->myfb = real_sys_read;
概念证明
#include <sys/types.h>
#define asmlinkage
#define __user
asmlinkage ssize_t (*real_sys_read)(unsigned int fd, char __user *buf, size_t count);
asmlinkage ssize_t hooked_sys_read(unsigned int fd, char __user *buf, size_t count);
typedef ssize_t (*ReadPointer)(unsigned int fd, char __user *data, size_t size);
typedef struct xyz_data
{
ReadPointer myfa;
ReadPointer myfb;
} xyz_data;
extern xyz_data getter(void);
xyz_data getter(void)
{
xyz_data data;
xyz_data *reader = &data;
reader->myfa = hooked_sys_read;
reader->myfb = real_sys_read;
// The next line fails to compile: assignment from incompatible pointer type
// reader->myfb = &real_sys_read;
reader->myfa = &hooked_sys_read;
reader->myfa = hooked_sys_read;
reader->myfa = *hooked_sys_read;
reader->myfa = **hooked_sys_read;
reader->myfa = ***hooked_sys_read;
reader->myfa = ****hooked_sys_read;
return *reader;
}
它编译干净。不过,这不是好的代码——单是重复的赋值就足以让它变得糟糕。