シナリオ
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;
(関数) ポインター変数のアドレスを に割り当てているvoid *
ため、オブジェクト ポインターを void ポインターに割り当てていますが、これは正当ですが、正しくありません。
合成
次の 2 つの関数型 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;
}
きれいにコンパイルされます。ただし、これは良いコードではありません — 代入を繰り返すだけで、コードが悪くなります。