2015-11-15 39 views
12

私はUbuntuで作業しています。私は、お互いの機能を使用する2つのカーネルモジュールを作ろうとしています。私の問題は、適切にコンパイルされたモジュールが得られていることです。しかし、シンボルはそれらのいずれかで解決されません。別のモジュールで定義されているシンボルの "Unknown symbol in module"でinsmodが失敗する

これらのモジュールをm1m2と呼びましょう。

m2輸出機能void func_m2(void)です。 m1がこの関数を呼び出しています。両方のモジュールが適切にコンパイルされます。

すべてコンパイルした後、最初にm2モジュールをロードする必要があります(func_m2関数をエクスポートしたため)。その後はm1モジュールをロードする必要があります。それでは、それを作ってみましょう:

[email protected]:~/development/kmodules/m2$ sudo insmod ./m2.ko 

は今、func_m2を使用しようとしているロードm1モジュールができます:

[email protected]:~/development/kmodules/m1$ sudo insmod ./m1.ko 
insmod: error inserting './m1.ko': -1 Unknown symbol in module 

次は私がログに見えるものです:だから

[email protected]:~/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への参照が解決されていないようです。面白い。それはシンボルテーブルに存在する場合のは確認してみましょう:あなたが見ることができるように、func_m2はシンボルテーブルに実際に存在している

[email protected]:~/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] 

。だからなぜm1をロードできませんか?

カーネルとLinuxのソース用に適切なLinuxヘッダーをインストールしました。 2.6.31-16-generic(私はx64を実行します)

ここでは、完全な画像を表示するために、ここにソースコードとMakefileを入れています。私はm1m2の両方のモジュールでこのテストに使用しました。

m1

モジュール:

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"); 

のMakefile:

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モジュール:

の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); 

のMakefile:

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をロードすることはできませんか?

誰かが答えることができれば助かります。

+0

https://serverfault.com/questions/124128/linux-says-a-kernel-module-has-an-unknown-symbol-but-another-loaded-module-prov –

答えて

3

は、ここで私はあなたのコードで見つかったいくつかの問題がある:

(A)。あなたの初期化関数と終了関数は静的で宣言され、適切に識別されるべきです。例えば、m1.cで - m2.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"); 
} 

繰り返しこの

(B)。同じMakefileを使用して、両方のモジュールを一緒にビルドします。 m1.cの既存のMakefileの出力を注意深く見れば、func_m2()が未定義であることを示す警告が表示されます。両方のモジュールがビルドされた後に「m1.ko」のinsmodのを発行する前に「m2.ko」に関するinsmodのを実行し、

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 

- とにかく、連結のMakefileは次のようになります。 dmesgで結果を確認してください。

また、ここでは、m1.cとm2.cの両方が同じディレクトリにあると仮定しています。彼らが別のディレクトリにいても、このテクニックはうまくいくでしょうが、それは面倒です。それらが異なるディレクトリにある場合は、次の操作を行います。

私はほとんど研究をせず、モジュールを別々のディレクトリに構築する方法を見つけました。私が使った例はあなたが持っているものよりずっと簡単ですが、おそらくそれは適応可能です。

私はm2_func ... ExportSymbolというディレクトリに

$ ls -CFR 
.: 
include/ Makefile mod1/ mod2/ 

./include: 
m2_func.h 

./mod1: 
Makefile module1.c 

./mod2: 
Makefile module2.c 

をファイルのマニフェスト次ています。トップレベルのMakefileは、として表示され

#ifndef M2_FUNC_H 
#define M2_FUNC_H 

void m2_func(void); 

#endif 

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は、それは*各Cファイルあたりの.koを生成して、私はあなたのメイクファイルを使用することはできません:

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); 

注:としてppear。 Makefileはその仕事をしています。 'ko'ファイルはカーネルオブジェクトファイルです。 .cソースファイルごとに1つずつ作成されます。これを回避する方法はありません。複数のkoファイルを必要としない場合は、すべてのコードを1つのソースファイルに入れてください。

+0

私によると、複数のCファイルを作成し、複数の.koファイルを作成することはできません。私は古いプロジェクトでたくさんの.cファイルを作っていましたが、.koファイルは1つしかありませんでした。途中で答えをありがとう。 –

4

m2をビルドすると、Module.symversファイルが作成されます。

このファイルをm1を構築している場所にコピーします。その後、m1を作り、それをinsmodします。

あなたはおそらくあなたが前にM1を構築し、警告していた、何かのように:

WARNING: "func_m2は" [/tmp/m1/m1.ko]未定義!

これは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ファイルを使用する方法は、 をお勧めしますが、特定の状況では実用的でない場合があります。

あなたは foo.koがbar.koからシンボルを必要とする2つのモジュールfoo.koとbar.koを、持っている場合は、あなたがそう 共通のトップレベルのkbuildファイルを使用することができ、トップレベルのkbuildファイル を使用します両方のモジュールは同じビルドでコンパイルされた です。

: は./bar/ < =がトップレベルのkbuildファイルは、次のようになりbar.ko

含まfoo.ko

./foo/ < =含まれています。次 ディレクトリレイアウトを考えてみましょう

$ ./Kbuild(または。/ Makefileの): OBJ-Y:= FOO /バー/

そして

$を実行するには、-C $ KDIR M = $ PWD

はその後、予想を行うと、フル で両方のモジュールをコンパイルします作りますいずれかのモジュールからのシンボルの知識。

外部モジュールが内蔵されている場合は、余分なModule.symversがModule.symversが ファイル、 ファイル使用は、カーネルに 定義されていないすべてのエクスポートされたシンボルを含む生成されます。 bar.koのシンボル にアクセスするには、bar.koの コンパイルからfoo.koが であるディレクトリにModule.symversファイルをコピーします。モジュールのビルド中に、kbuildは、外部の モジュールのディレクトリにある Module.symversファイルを読み込み、ビルドが完了すると、 のすべてのシンボルが定義されていて、部分ではない、新しい Module.symversファイルが作成されますカーネルの

使用それは 別のモジュールからModule.symversをコピーすることは非現実的である場合は、ビルドファイルにKBUILD_EXTRA_SYMBOLSにファイルのリスト を分離スペースを割り当てることができ、変数KBUILD_EXTRA_SYMBOLS を「作ります」。 これらのファイルは、シンボルテーブルの の初期化中にmodpostによってロードされます。

関連する問題