关于执行ioctl函数,在32位模式下编译和在64位os上编译64位模式有什么不同?

问题描述:

我有一个64位的企业单位的SuSE 11 我有打开HIDRAW设备并在其上运行的ioctl函数来得到这种设备的原始信息象下面这样的应用程序:关于执行ioctl函数,在32位模式下编译和在64位os上编译64位模式有什么不同?

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

如果我编译这个程序中64位模式没有错误,没有问题,当我执行应用程序时,ioctl函数可以正常工作。

g++ main.cpp 

如果我在32位模式下编译这个程序,也没有错误,也没有问题。但是当我执行应用程序的ioctl函数返回EINVAL错误(错误= 22,参数无效)

g++ -m32 main.cpp 

什么问题?

注:

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

Linux ioctl定义和兼容性层是一个引人入胜的话题,我刚刚撞见了我的头。

通常ioctl定义使用一个系列的宏_IOW/_IOR等人即把你的参数类型名字作为参考,有一个神奇的数字和顺序值是被改写的,给你你的IOCTL参数值一起(如HIDIOCGRAWINFO) 。类型名称用于将sizeof(arg_type)编码到定义中。这意味着在用户空间中使用的类型决定了由ioctl宏生成的 - 即HIDIOCGRAWINFO可能会因包含条件而异。

这里是第一点,其中32位和64位不同,sizeof可能会有所不同,取决于打包,使用模糊的数据大小(如长),​​但特别是(和不可避免的),如果您使用指针参数。因此,在这种情况下,需要支持32位客户端的64位内核模块需要定义兼容性参数类型以匹配参数类型的32位等效版本的布局,从而与32位兼容的ioctl匹配。这些32位等效定义使用称为compat的内核设施/层。

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

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

我所看到的是CONFIG_COMPAT定义的32位程序将生成代码,提供ioctl S到ioctl_compat回调,即使64位确实可以产生相同的ioctl值(例如,在你的案件)。所以驱动程序编写者需要确保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

+0

和:http://git.kernel.org/?p=linux/kernel/git/stable/linux-stable.git;a=commit;h=ae5e49c79c051ea1d5ca91cbd4a0d22189067ba3 – Greg 2012-03-27 04:36:49

的问题可能是devinfo结构程序传递给ioctl功能之间的不匹配。

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

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

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

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

+1

我无法理解你的答案。 __u32在32位和64位都是4个字节。 以及__s16在32位和64位都是2个字节。 和sizeof(hidraw_devinfo)的长度是8个字节(考虑操作系统打包)。 – 2012-02-13 12:54:11

+0

另一种解释是内核模块不希望32位用户程序调用它。 (必须有一些特殊的东西来接受它们。)但是,如果是这种情况,我会惊讶于'-EINVAL'错误。 – 2012-02-13 16:20:25