3

私は64ビットのEnterpriceSuSE11を持っています。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;
}
4

2 に答える 2

4

Linuxioctlの定義と互換性レイヤーは、私が頭を悩ませたばかりの魅力的なトピックです。

通常ioctl、定義では、引数のタイプ名を参照として使用するマクロのファミリー_IOW / _IOR et alと、ioctl引数値を提供するために変更されたマジックナンバーと序数を使用します(例HIDIOCGRAWINFO)。タイプ名は、定義にエンコードするために使用されsizeof(arg_type)ます。これは、ユーザースペースで使用されるタイプによって、マクロによって生成されるioctlが決まることを意味します。つまり、HIDIOCGRAWINFOは、インクルード条件に基づいて変化する可能性があります。

これが32ビットと64ビットが異なる最初のポイントです。sizeofパッキングによっては、あいまいなデータサイズ(長いなど)の使用が異なる場合がありますが、特に(そして不可避的に)ポインタ引数を使用する場合は異なります。したがって、この場合、32ビットクライアントをサポートする必要がある64ビットカーネルモジュールは、互換性引数タイプを定義して、引数タイプと同等の32ビットのレイアウトと一致するようにします。したがって、32ビット互換ioctlを定義します。これらの32ビットの同等の定義は、と呼ばれるカーネル機能/レイヤーを利用しますcompat

あなたの場合、sizeof()それはあなたがたどっている道ではないので同じです-しかし、起こっている可能性のあることの全体を理解することは重要です。

さらに、カーネル構成は、32ビットおよび64ビットをサポートする負担を軽減するためCONFIG_COMPATにsys-callラッパー(特にユーザー/カーネルインターフェイスwrtを囲むコード)を変更するものを定義する場合があります。ioctlこの一部には、と呼ばれる互換性ioctlコールバックが含まれioctl_compatます。

私が見たのはCONFIG_COMPAT、32ビットプログラムが64ビットと同じ値を生成できる場合でも(たとえば、あなたの場合)、コールバックにioctlsを配信するコードを生成することを定義したものです。したがって、ドライバーライターは、特別な(異なる)32ビット互換タイプと通常の「64ビットまたは変更されていない32ビット」タイプの両方を処理することを確認する必要があります。ioctl_compatioctlioctl_compatioctl

したがって、32ビットのみおよび64ビットのみのシステム(CONFIG_COMPATなし)で設計およびテストされたカーネルモジュールは、32ビットおよび64ビットのプログラムでは機能しますが、両方をサポートするプログラムでは機能しません。

したがって、HIDを見ると、これは2.6.38で追加されたことがわかります。

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

于 2012-03-27T04:35:44.557 に答える
3

devinfo問題はおそらく、プログラムがioctl関数に渡す構造間の不一致です。

64ビットシステムでの作業だと思います。したがって、カーネルは64ビットで実行され、(で)通信しているカーネルモジュールioctlも64ビットです。

ユーザープログラムを64ビットでコンパイルする場合devinfo、カーネルモジュールとユーザープログラムの定義は同じです。

ユーザープログラムを32ビットでコンパイルするdevinfoと、カーネルモジュールでの定義がユーザープログラムでの定義と異なります。実際、32ビットでは、主longにポインタなど、一部の型のサイズが変化します。したがって、プログラムは特定のサイズの構造を作成し、カーネルモジュールは受け取ったデータを異なる方法で解釈します。カーネルモジュールは、配置した位置でカーネルモジュールを検索しないため、与えられた値を理解していない可能性があります。

解決策は、構造体の定義に注意を払いdevinfo、32ビットと64ビットでコンパイルするときに同じバイナリ表現を持つようにすることです。

于 2012-02-13T11:58:53.707 に答える