在64位操作系统上以32位模式和64位模式编译ioctl函数的执行有什么不同?

2024-05-08

我有 64 位 Enterprise 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

有什么问题?

Note:

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

Linux ioctl定义和兼容性层是一个令人着迷的话题,我刚刚对此进行了猛烈的抨击。

通常ioctl定义使用一系列宏 _IOW/_IOR 等,它们将您的参数类型名称作为参考,以及一个幻数和序数值,这些数值和序数值被修改为您的 ioctl 参数值(例如HIDIOCGRAWINFO)。类型名称用于编码sizeof(arg_type)进入定义。这意味着使用的类型user空间决定了value由产生的ioctl宏 - 即 HIDIOCGRAWINFO 可能会根据包含条件而有所不同。

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

在你的情况下sizeof()是一样的,所以这不是你正在走的路——但了解可能发生的全部事情很重要。

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

我所看到的是CONFIG_COMPAT定义 32 位程序将生成提供以下功能的代码ioctlioctl_compat回调,即使它could生成相同的ioctl值与 64 位相同(例如,在您的情况下)。所以驱动程序编写者需要确保ioctl_compat把手both特殊(不同)32位兼容ioctlTYPE 和普通的“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 http://lxr.linux.no/#linux+v2.6.38/drivers/hid/hidraw.c#L347

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在64位操作系统上以32位模式和64位模式编译ioctl函数的执行有什么不同? 的相关文章

随机推荐