Чем отличается компиляция в 32-битном режиме и 64-битном режиме на 64-битной ОС от выполнения функции ioctl? - PullRequest
3 голосов
/ 13 февраля 2012

У меня 64 битная Предприятие SuSE 11 У меня есть приложение, которое открывает устройство HIDRAW и использует на нем функцию ioctl для получения необработанной информации с этого устройства, как показано ниже:

struct hidraw_devinfo devinfo;
int fd = open("/dev/hidraw0", 0);
int ret = ioctl(fd, HIDIOCGRAWINFO, &devinfo);
...

Если я скомпилирую эту программу в 64-битном режиме, ошибок и ошибок не возникнет, и при запуске приложения функция ioctl будет работать правильно.

g++ main.cpp

Если я выполню эту программу в 32-битном режиме, то также не будет ошибок и проблем. но когда я выполняю приложение, функция ioctl возвращает ошибку EINVAL (errno = 22, неверный аргумент)

g++ -m32 main.cpp

в чем проблема?

Примечание:

struct hidraw_devinfo 
{
     __u32 bustype;
     __s16 vendor;
     __s16 product;
}

Ответы [ 2 ]

3 голосов
/ 27 марта 2012

Linux ioctl определения и уровни совместимости - увлекательная тема, против которой я только что разбил голову.

Как правило, ioctl определения используют семейство макросов _IOW / _IOR и др., Которые принимают имя типа аргумента в качестве ссылки, вместе с магическим числом и порядковым значением, которые подставляются для получения значения аргумента ioctl (например, HIDIOCGRAWINFO). Имя типа используется для кодирования sizeof(arg_type) в определении. Это означает, что тип, используемый в user space, определяет значение , сгенерированное макросом ioctl - т.е. HIDIOCGRAWINFO может варьироваться в зависимости от условий включения.

Здесь первая точка, в которой 32- и 64-разрядные различия отличаются, sizeof может отличаться в зависимости от упаковки, использования нечетких размеров данных (например, длинных), но особенно (и неизбежно), если вы используете указатель аргумент. Таким образом, в этом случае 64-битный модуль ядра, который требуется для поддержки 32-битных клиентов, должен определить тип аргумента совместимости, чтобы он соответствовал макету 32-битного эквивалента типа аргумента и, следовательно, 32-битного совместимого ioctl. В этих 32-битных эквивалентных определениях используется ядро ​​/ слой, называемый compat.

В вашем случае sizeof() - это то же самое, так что это не тот путь, по которому вы идете, но важно понимать все, что может происходить.

Кроме того, конфигурация ядра может определять CONFIG_COMPAT, который изменяет оболочки системного вызова (особенно код, окружающий интерфейс пользователя / ядра по отношению к ioctl), чтобы облегчить бремя поддержки 32- и 64-битных систем. Часть этого включает в себя ioctl обратный вызов совместимости под названием ioctl_compat.

То, что я видел, с CONFIG_COMPAT определено, что 32-битные программы будут генерировать код, который доставляет ioctl s для обратного вызова ioctl_compat, даже если может генерировать то же самое ioctl значение как 64-битное (например, в вашем случае). Поэтому пишущий драйвер должен убедиться, что ioctl_compat обрабатывает и специальные (разные) 32-битные совместимые ioctl ТИПЫ и обычные "64-битные - или неизмененные 32-битные" типы.

Таким образом, модуль ядра, разработанный и протестированный только в 32-разрядных и 64-разрядных системах (без CONFIG_COMPAT), может работать для 32- и 64-разрядных программ, но не для той, которая поддерживает оба.

Итак, глядя в HID, я вижу, что это было добавлено в 2.6.38:

http://lxr.linux.no/#linux+v2.6.38/drivers/hid/hidraw.c#L347

3 голосов
/ 13 февраля 2012

Возможно, проблема в несоответствии структуры devinfo, которую ваша программа передает функции ioctl.

Я полагаю, вы работаете в 64-битной системе. Таким образом, ваше ядро ​​работает в 64 битах, а модуль ядра, с которым вы разговариваете (с ioctl), также 64 бит.

Когда вы компилируете свою пользовательскую программу в 64 бита, определение devinfo в модуле ядра и в пользовательской программе одинаково.

Когда вы компилируете свою пользовательскую программу в 32 бита, определение devinfo в модуле ядра отличается от его определения в вашей пользовательской программе. Действительно, в 32 битах размер некоторых типов изменяется: в основном long и указатели. Таким образом, ваша программа создает структуру определенного размера, а модуль ядра интерпретирует полученные данные по-разному. Модуль ядра, вероятно, не понимает значение, которое вы ему даете, потому что он не ищет его в позиции, в которую вы его поместили.

Решение состоит в том, чтобы обратить внимание на определение структуры devinfo, чтобы она имела одинаковое двоичное представление при компиляции для 32 бит и для 64 бит.

...