有关ioctl函数执行的32位模式和64位操作系统64位模式编译有何不同?

时间:2012-02-13 09:37:22

标签: linux gcc g++ 32bit-64bit ioctl

我有64位Enterprice 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 个答案:

答案 0 :(得分:3)

问题可能是您的程序传递给devinfo函数的ioctl结构不匹配。

我猜你的工作在64位系统上。因此,你的内核以64位运行,你正在与之交谈的内核模块(ioctl)也是64位。

当您以64位编译用户程序时,内核模块和用户程序中的devinfo定义是相同的。

以32位编译用户程序时,内核模块中的devinfo定义与用户程序中的定义不同。实际上,在32位中,某些类型的大小会发生变化:主要是long和指针。因此,您的程序创建一定大小的结构,内核模块以不同方式解释它接收的数据。内核模块可能无法理解您给它的值,因为它不会在您放置它的位置查找它。

解决方案是注意devinfo结构的定义,以便在编译32位和64位时具有相同的二进制表示。

答案 1 :(得分:3)

Linux ioctl定义和兼容性层是一个引人入胜的话题。

通常ioctl定义使用一系列宏_IOW / _IOR等,它们将您的参数type-name作为参考,以及一个幻数和序数值,它们被赋予您的ioctl参数值(例如HIDIOCGRAWINFO)。 type-name用于将sizeof(arg_type)编码到定义中。这意味着 user 空间中使用的类型决定了ioctl宏生成的 - 即HIDIOCGRAWINFO可能会因包含条件而异。

这是32位和64位不同的第一点,sizeof可能会有所不同,具体取决于打包,使用模糊的数据大小(例如长),但如果使用的话,尤其(并且不可避免地)指针参数。因此,在这种情况下,需要支持32位客户端需要的64位内核模块需要定义兼容性参数类型以匹配参数类型的32位等效的布局,从而匹配32位兼容的ioctl。这些32位等效定义使用名为compat的内核工具/层。

在你的情况下,sizeof()是相同的,所以这不是你正在采取的路径 - 但重要的是要了解可能发生的事情。

此外,内核配置可以定义CONFIG_COMPAT,它会更改sys-call包装器(尤其是围绕用户/内核接口wrt ioctl的代码),以减轻支持32-和64-的负担位。部分内容包括名为ioctl的兼容性ioctl_compat回调。

我看到的是CONFIG_COMPAT定义了32位程序会生成代码,ioctl回调ioctl_compat,即使它可以生成与64位相同的ioctl值(例如在您的情况下)。因此驱动程序编写者需要确保ioctl_compat处理两者特殊(不同)32位兼容ioctl TYPE和正常“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