如何使用LD_PRELOAD来包装ioctl(int d,无符号长请求,…)?

这里是我使用LD_PRELOAD封装函数的模板:

int gettimeofday(struct timeval *tv, struct timezone *tz) { static int (*gettimeofday_real)(struct timeval *tv, struct timezone *tz)=NULL; if (!gettimeofday_real) gettimeofday_real=dlsym(RTLD_NEXT,"gettimeofday"); return gettimeofday_real(tv, tz); } 

我意识到,虽然ioctl似乎有以下签名:

  int ioctl(int d, unsigned long request, ...); 

我怎么能用类似的方式把它包裹起来?

尽管John Bollinger根据其在ioctl.h原型是正确的,但ioctl()是一个可变参数函数,实际上并不是这样。

请参阅本书“ Linux设备驱动程序”中的 引用

原型在Unix系统调用列表中突出,因为它们通常将函数标记为具有可变数目的参数。 然而,在一个真实的系统中,一个系统调用实际上不能具有可变数目的参数。 系统调用必须有一个定义良好的原型,因为用户程序只能通过硬件“门”访问它们。 因此,原型中的点不是可变数量的参数,而是单个可选参数,传统上被标识为char * argp。 这些点只是为了防止编译期间的类型检查。

所以你可以写下你的suso ioctl() ,如下所示:

 int ioctl(int d, unsigned long request, char *argp) { /* follow the same recipe as for your example gettimeofday() */ return ioctl_real(d, request, argp); } 

如果你只是想建立一个与LD_PRELOAD一起使用的包装库,那么你的ioctl签名与sys/ioctl.h签名相矛盾的sys/ioctl.h是不相干的:连接器不检查类型,你的包装库的假ioctl将被调用与没有LD_PRELOAD的实际相同的参数

对于一个可变参数函数来说,没有可移植的方法来将其可变参数转发给另一个可变参数函数。 部分原因是编译时必须知道实际参数的数量和大小,以便编译器构建可变参数调用,但在被调用函数内部它们不是静态的(即使参数化方式)。