如何使用LD_PRELOAD包装ioctl(int d,unsigned long request,...)?

时间:2015-02-11 19:11:27

标签: c linux system-calls ld-preload

这是我用于使用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, ...);

考虑到签名中的...,我怎么能以类似的方式包装呢?

2 个答案:

答案 0 :(得分:6)

尽管John Bollinger的正确性在ioctl.h中,ioctl()是一个可变函数,但实际上并非如此。

请参阅书籍this quote

中的Linux Device Drivers
  

原型在Unix系统调用列表中脱颖而出因为   点,通常将函数标记为具有可变数字   论点。但是,在实际系统中,系统调用实际上是不可能的   具有可变数量的参数。系统调用必须有一个   定义良好的原型,因为用户程序只能访问它们   通过硬件"盖。"因此,原型中的点   表示不是可变数量的参数,而是单个可选参数   参数,传统上标识为char * argp。点很简单   在编译期间防止类型检查。

所以你可以按如下方式编写你的简历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中的签名相矛盾的事实无关紧要:链接器不会检查类型和你的包装库的假ioctl将使用与没有LD_PRELOAD

的实际参数完全相同的参数调用

答案 1 :(得分:1)

一个可变参数函数没有可移植的方法将其可变参数转发给另一个可变参数函数。在某种程度上,这是因为编译器在编译时必须知道实际参数的数量和大小,以便构造可变参数调用,但它们在被调用函数内部并不是静态知道的(甚至不是以参数方式)。