关于执行ioctl函数,在32位模式下编译和64位os上的64位模式有什么不同? [英] What's different between compiling in 32bit mode and 64bit mode on 64bit os about execution of ioctl function?

查看:659
本文介绍了关于执行ioctl函数,在32位模式下编译和64位os上的64位模式有什么不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个64位的Enterprice SuSE 11
我有一个应用程序,它打开一个HIDRAW设备,并在其上运行一个ioctl函数,以从此设备获取原始信息,如下所示:

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

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


$ b

  g ++ main.cpp 

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

  g ++ -m32 main.cpp 

有什么问题?



注意:

  struct hidraw_devinfo 
{
__u32 bustype;
__s16厂商;
__s16产品;


解决方案

Linux ioctl 定义和兼容性层是一个引人入胜的话题,我只是抨击我的头。



通常 ioctl 定义使用一系列宏_IOW / _IOR等,它们将参数类型名称作为参考,以及用于给出您的ioctl参数值的幻数和序数值(例如 HIDIOCGRAWINFO )。类型名称用于将 sizeof(arg_type)编码到定义中。这意味着 user 空间中使用的类型决定了由 ioctl 宏生成的 - 即HIDIOCGRAWINFO可能会根据在包含条件中。

以下是32位和64位不同的第一点, sizeof 可能不同,取决于包装,使用模糊的数据大小(例如长),但是如果使用指针参数尤其(并且不可避免)。因此,在这种情况下,需要支持32位客户端的64位内核模块需要定义兼容性参数类型,以匹配参数类型的32位等效版本以及32位兼容ioctl的布局。这些32位等价的定义使用了一个名为 compat 的内核工具/层。在你的情况下, code> sizeof()是相同的,所以这不是你正在使用的路径 - 但它对于理解可能发生的所有事情很重要。



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



我看到的是 CONFIG_COMPAT 定义了32位程序将生成的代码将 ioctl s传递给 ioctl_compat 回调,即使它可以生成相同的 ioctl 值为64位(例如你的情况)。因此,驱动程序编写者需要确保 ioctl_compat 处理 特殊(不同的)32位兼容的 ioctl code> TYPEs和正常的64位或不变的32位类型。所以,一个内核模块仅在32位设计和测试和64位只有系统(没有CONFIG_COMPAT)可能适用于32位和64位程序,但不适用于同时支持这两种系统的程序。



这是在2.6.38中添加的:

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


I have a 64 bit Enterprice SuSE 11 I have an application which open a HIDRAW device and operate an ioctl function on it to get raw info from this device like below:

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

If I compile this program in 64 bit mode there is no error and no problem and when I execute the application the ioctl function works properly.

g++ main.cpp

If I complie this program in 32 bit mode there is also no error and no problem. but when I execute the application the ioctl function return EINVAL error(errno = 22 , Invalid Argument)

g++ -m32 main.cpp

what's the problem?

Note:

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

解决方案

Linux ioctl definitions and compatibility layers are a fascinating topic I've just bashed my head against.

Typically ioctl definitions use a family of macros _IOW/_IOR et al that take your argument type-name as a reference, along with a magic number and ordinal value that are munged to give you your ioctl argument value (eg HIDIOCGRAWINFO). The type-name is used to encode sizeof(arg_type) into the definition. This means that the type used in user space determines the value generated by the ioctl macro - ie HIDIOCGRAWINFO may vary based on include conditions.

Here is the first point where 32- and 64-bit differ, the sizeof may differ, depending on packing, use of vague data-sizes (eg long), but especially (and unavoidably) if you use a pointer argument. So in this case a 64-bit kernel module what wants to support 32-bit clients needs do define a compatibility argument-type to match the layout of the 32-bit equivalent of the argument type and thus a 32-bit compatible ioctl. These 32-bit equivalent definitions make use of a kernel facility/layer called compat.

In your case the sizeof() is the same so that is not the path you are taking - but its important to understand the whole of what could be happening.

In addition a kernel configuration may define CONFIG_COMPAT which changes the sys-call wrappers (especially the code surrounding the user/kernel interface wrt ioctl) to ease the burden of supporting 32- and 64-bit. Part of this includes a compatibility ioctl callback called ioctl_compat.

What I've seen is with CONFIG_COMPAT defined that 32-bit programs will generate code that delivers ioctls to the ioctl_compat callback, even if it could generate the same ioctl value as 64-bit does (eg in your case). So the driver writer needs to make sure that ioctl_compat handles both the special (different) 32-bit compatible ioctl TYPEs and the normal "64-bit - or unchanged 32-bit" types.

So a kernel-module designed and tested on 32-bit only and 64-bit only systems (without CONFIG_COMPAT) may work for 32- and 64-bit programs, but not for one which supports both.

So looking in HID I see this was added in 2.6.38:

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

这篇关于关于执行ioctl函数,在32位模式下编译和64位os上的64位模式有什么不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆