Как обернуть ioctl(int d, unsigned long request, ...), используя 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 ответа
Хотя Джон Боллинджер прав в этом согласно своему прототипу в ioctl.h
, ioctl()
это вариадная функция, на практике это не так.
Посмотрите, например, эту цитату из книги Драйверы устройств Linux
Прототип выделяется в списке системных вызовов Unix из-за точек, которые обычно отмечают функцию как имеющую переменное число аргументов. Однако в реальной системе системный вызов не может иметь переменное количество аргументов. Системные вызовы должны иметь четко определенный прототип, потому что пользовательские программы могут получить к ним доступ только через аппаратные "ворота". Поэтому точки в прототипе представляют не переменное число аргументов, а один необязательный аргумент, традиционно обозначаемый как char * argp. Точки просто существуют, чтобы предотвратить проверку типов во время компиляции.
Таким образом, вы можете написать свой susbtitute 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
Не существует переносимого способа для одной функции с переменными параметрами пересылать свои аргументы с переменными параметрами в другую функцию с переменными числами. Частично это связано с тем, что число и размер фактических аргументов должны быть известны во время компиляции, чтобы компилятор мог создать вызов переменной, но они не являются статически известными (даже параметрическим способом) внутри вызываемой функции.