デバイスドライバーにさまざまな機能を提供するカーネルモジュールとしてAPIを作成しています。mycode.cに3つの関数を書きました。次に、モジュールをビルドしてロードし、mycode.hを<kernel> / include/linuxにコピーしました。デバイスドライバーには、#include <linux / mycode.h>があり、これら3つの関数を呼び出します。しかし、ドライバーモジュールをビルドすると、これらの関数が未定義であるという3つのリンカー警告が表示されます。
ノート:
- 関数はmycode.hでexternとして宣言されています
- 関数は、mycode.cのEXPORT_SYMBOL(func_name)を使用してエクスポートされます。
- コマンドnmmycode.koを実行すると、3つの関数すべてがシンボルテーブルで使用可能であることが示されます(それらの横にある大文字のTは、シンボルがテキスト(コード)セクションにあることを意味します)
- モジュールをロードした後、コマンドgrep func_name / proc / kallsymsは、3つの関数すべてがロードされていることを示します。
したがって、明らかに関数は正しくエクスポートされており、カーネルはそれらが何でどこにあるかを認識しています。では、なぜドライバーはそれらの定義を見ることができないのでしょうか?私が何を見逃しているのか分かりますか?
編集:私はこれに関するいくつかの情報をここで見つけました: http ://www.kernel.org/doc/Documentation/kbuild/modules.txt
外部モジュールが別の外部モジュールからエクスポートされたシンボルを使用する場合があります。kbuildは、未定義のシンボルに関する警告を吐き出さないように、すべてのシンボルについて完全な知識を持っている必要があります。この状況には3つの解決策があります。
注:トップレベルのkbuildファイルを使用する方法をお勧めしますが、特定の状況では実用的でない場合があります。
トップレベルのkbuildファイルを使用するfoo.koとbar.koの2つのモジュールがあり、foo.koがbar.koのシンボルを必要とする場合は、共通のトップレベルのkbuildファイルを使用して、両方のモジュールが同じようにコンパイルされるようにすることができます。建てる。次のディレクトリレイアウトを検討してください。
./foo/ <= contains foo.ko ./bar/ <= contains bar.ko
最上位のkbuildファイルは次のようになります。
#./Kbuild (or ./Makefile): obj-y := foo/ bar/
そして実行
$ make -C $KDIR M=$PWD
次に、期待どおりに実行し、いずれかのモジュールのシンボルに関する完全な知識を使用して両方のモジュールをコンパイルします。
追加のModule.symversファイルを使用する外部モジュールがビルドされると、カーネルで定義されていないすべてのエクスポートされたシンボルを含むModule.symversファイルが生成されます。bar.koからシンボルにアクセスするには、bar.koのコンパイルからmodule.symversファイルをfoo.koがビルドされているディレクトリにコピーします。モジュールのビルド中に、kbuildは外部モジュールのディレクトリにあるModule.symversファイルを読み取り、ビルドが完了すると、カーネルの一部ではなく、定義されたすべてのシンボルの合計を含む新しいModule.symversファイルが作成されます。
「make」変数KBUILD_EXTRA_SYMBOLSを使用する別のモジュールからModule.symversをコピーすることが実際的でない場合は、スペースで区切られたファイルのリストをビルドファイルのKBUILD_EXTRA_SYMBOLSに割り当てることができます。これらのファイルは、シンボルテーブルの初期化中にmodpostによってロードされます。
しかし、これら3つのソリューションすべてで、ドライバーが私のAPIを使用するには、新しいMakefileを作成するか、Module.symversファイルに直接アクセスする必要がありますか?それは少し不便に思えます。私は、彼らが私のヘッダーファイルを#includeして、うまくいくことを望んでいました。他に選択肢はありませんか?