私はUbuntuで働いています。私はお互いの機能を使用する2つのカーネルモジュールを作成しようとしています。私の問題は、モジュールが適切にコンパイルされたのに、そのうちの1つでシンボルが解決されないことです。
物事を簡単にするために、これらのモジュールを_m1
_および_m2
_として呼び出しましょう。
m2は関数void func_m2(void)
をエクスポートしています。 _m1
_はこの関数を呼び出しています。両方のモジュールが正しくコンパイルされます。
すべてコンパイルした後、最初に_m2
_モジュールを(_func_m2
_関数をエクスポートしたため)ロードし、その後_m1
_モジュールをロードする必要があります。それでは、作りましょう:
_volodymyr@sv1:~/development/kmodules/m2$ Sudo insmod ./m2.ko
_
ここで、_m1
_を使用しようとしている_func_m2
_モジュールをロードしましょう。
_volodymyr@sv1:~/development/kmodules/m1$ Sudo insmod ./m1.ko
insmod: error inserting './m1.ko': -1 Unknown symbol in module
_
ログに表示されるのは次のとおりです。
_volodymyr@sv1:~/development/kmodules/m1$ dmesg | tail
[ 3938.166616] Loading m2 module ...
[ 3963.078055] m1: no symbol version for func_m2
[ 3963.078059] m1: Unknown symbol func_m2
_
したがって、シンボル_func_m2
_への参照は解決されていないようです。面白い。シンボルテーブルに存在するかどうかを確認しましょう。
_volodymyr@sv1:~/development/kmodules$ cat /proc/kallsyms | grep 'func_m2'
ffffffffa00530d0 r __ksymtab_func_m2 [m2]
ffffffffa00530e8 r __kstrtab_func_m2 [m2]
ffffffffa00530e0 r __kcrctab_func_m2 [m2]
ffffffffa0053000 T func_m2 [m2]
000000004edd543f a __crc_func_m2 [m2]
_
ご覧のとおり、_func_m2
_は実際にはシンボルテーブルに存在します。では、なぜ_m1
_をロードできないのですか?
カーネルおよびLinuxソース用にLinuxヘッダーを適切にインストールしました。カーネルに変更を加えたわけではありません。変更されておらず、バージョンは2.6.31-16-generic(x64を実行しています)
ここで、全体像を示すために、ここで_m1
_および_m2
_モジュールの両方のこのテストに使用したソースコードとMakefileを配置します。
_m1
_ module:
m1.c:
_#include <linux/module.h>
#include <linux/kernel.h>
extern void func_m2(void);
int hello_start(void)
{
printk(KERN_INFO "Loading m1 module ...\n");
func_m2();
return 0;
}
void hello_end(void)
{
printk(KERN_INFO "Unloading m1 ...\n");
}
module_init(hello_start);
module_exit(hello_end);
MODULE_LICENSE("GPL");
_
メイクファイル:
_obj-m := m1.o
all:
make -C /lib/modules/$(Shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(Shell uname -r)/build M=$(PWD) clean
_
_m2
_ module:
m2.c:
_#include <linux/module.h>
#include <linux/kernel.h>
int hello_start(void)
{
printk(KERN_INFO "Loading m2 module ...\n");
return 0;
}
void hello_end(void)
{
printk(KERN_INFO "Unloading m2 ...\n");
}
void func_m2(void)
{
printk(KERN_INFO "This a function in m2\n");
}
module_init(hello_start);
module_exit(hello_end);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(func_m2);
_
メイクファイル:
_obj-m := m2.o
export-objs := m2.o
all:
make -C /lib/modules/$(Shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(Shell uname -r)/build M=$(PWD) clean
_
基本的に私の質問は:なぜ_m1
_をロードできないのですか?
誰かが答えてくれると助かります。
あなたのコードで見つけたいくつかの問題は次のとおりです。
(a)。初期化および終了関数は静的に宣言され、適切に識別される必要があります。たとえば、m1.cでは-
static int __init hello_start(void)
{
printk(KERN_INFO "Loading m1 module ...\n");
func_m2();
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_INFO "Unloading m1 ...\n");
}
M2.cについてこれを繰り返します
(b)。同じMakefileを使用して、両方のモジュールを一緒にビルドします。 m1.cの既存のMakefileの出力をよく見ると、func_m2()が未定義であることを示す警告が表示されます。とにかく、統合されたMakefileは次のようになります-
SRCS = m1.c m2.c
OBJS = $(SRCS:.c=.o)
obj-m += $(OBJS)
EXTRA_CFLAGS = -O2
all:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean
$(RM) Module.markers modules.order
両方のモジュールをビルドしたら、「m1.ko」のinsmodを発行する前に「m2.ko」でinsmodを実行します。 dmesgで結果を確認します。
また、ここでは、m1.cとm2.cの両方が同じディレクトリにあると想定しています。それらが異なるディレクトリにある場合でも、この手法は機能しますが、面倒です。それらが異なるディレクトリにある場合は、次の手順を実行します。
私はほとんど調査をせず、別々のディレクトリにモジュールを構築する方法を見つけました。私が使用した例は、あなたが持っているものよりもはるかに単純ですが、おそらく適応可能です。
ExportSymbolというディレクトリにファイルのマニフェストがあります...
$ ls -CFR
.:
include/ Makefile mod1/ mod2/
./include:
m2_func.h
./mod1:
Makefile module1.c
./mod2:
Makefile module2.c
M2_func.hは次のように表示されます。
#ifndef M2_FUNC_H
#define M2_FUNC_H
void m2_func(void);
#endif
最上位のMakefileは次のように表示されます。
obj-y := mod1/ mod2/
all:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean
$(RM) Module.markers modules.order
Mod1 /にあるMakefileとmodule1.cは、次のように表示されます。
SRCS = module1.c
OBJS = $(SRCS:.c=.o)
obj-m += $(OBJS)
EXTRA_CFLAGS += -I${PWD}/include
all:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean
$(RM) Module.markers modules.order
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_start(void)
{
printk(KERN_INFO "Loading m1 module ...\n");
m2_func();
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_INFO "Unloading m1 ...\n");
}
module_init(hello_start);
module_exit(hello_end);
MODULE_LICENSE("GPL");
Mod2 /にあるMakefileとmodule2.cは、次のように表示されます。
SRCS = module2.c
OBJS = $(SRCS:.c=.o)
obj-m += $(OBJS)
EXTRA_CFLAGS += -I${PWD}/include
all:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) modules
clean:
$(MAKE) -C /lib/modules/`uname -r`/build M=$(PWD) clean
$(RM) Module.markers modules.order
#include "m2_func.h"
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_start(void)
{
printk(KERN_INFO "Loading m2 module ...\n");
return 0;
}
static void __exit hello_end(void)
{
printk(KERN_INFO "Unloading m2 ...\n");
}
void m2_func(void)
{
printk(KERN_INFO "This a function in m2\n");
}
module_init(hello_start);
module_exit(hello_end);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(m2_func);
注:各cファイルごとに* .koを生成するため、メイクファイルを使用できません。 Makefileはその仕事をしています。 「ko」ファイルはカーネルオブジェクトファイルです。各.cソースファイルに1つずつあります。これを回避する方法はありません。複数のkoファイルが必要ない場合は、すべてのコードを1つのソースファイルに入れます。
M2をビルドすると、Module.symvers
ファイルが作成されます。
このファイルをm1を構築している場所にコピーします。次に、m1を作成し、それをinsmodします。
前にm1をビルドしていたときに、おそらく次のような警告が表示されました。
警告: "func_m2" [/tmp/m1/m1.ko] undefined!
これは、m2モジュールからModule.symvers
を使用すると消えます。
http://www.kernel.org/doc/Documentation/kbuild/modules.txt から:
--- 6.2シンボルと外部モジュール
外部モジュールをビルドする場合、ビルドシステムはカーネルからシンボルにアクセスして、すべての外部シンボルが定義されているかどうかを確認する必要があります。これは、MODPOSTステップで行われます。 modpostは、カーネルソースツリーからModule.symversを読み取ることにより、シンボルを取得します。 Module.symversファイルが外部モジュールが構築されているディレクトリに存在する場合、このファイルも読み込まれます。 MODPOSTステップ中に、カーネルで定義されていないエクスポートされたすべてのシンボルを含む新しいModule.symversファイルが書き込まれます。
そして、これも同じファイルから読む価値があります:
--- 6.3別の外部モジュールからのシンボル
外部モジュールは、別の外部モジュールからエクスポートされたシンボルを使用する場合があります。 kbuildは、未定義のシンボルに関する警告を吐き出すことを避けるために、すべてのシンボルの完全な知識が必要です。この状況には3つの解決策があります。
注:最上位のkbuildファイルを使用する方法が推奨されますが、特定の状況では実用的ではない場合があります。
トップレベルのkbuildファイルを使用するfoo.koとbar.koの2つのモジュールがあり、foo.koがbar.koからのシンボルを必要とする場合、両方のモジュールが同じようにコンパイルされるように共通のトップレベルkbuildファイルを使用できます。ビルドします。次のディレクトリレイアウトを検討してください。
./foo/ <=はfoo.koを含む./bar/ <=はbar.koを含む
トップレベルのkbuildファイルは次のようになります。
$ ./Kbuild(または./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によってロードされます。