module_layout


lkmをコンパイルしたら、WARNING: "module_layout" [/home/kitamura/lkm/euid.ko] undefined!のメッセージが表示されました。lkmは問題なく動作しましたが何故ということで調べてみた結果です。

結論から言うと、母艦カーネルが CONFIG_MODVERSIONSで作成されていないのに、LKMのコンパイルではCONFIG_MODVERSIONSが設定されていますよ。との警告です。CONFIG_MODVERSIONSでカーネルをコンパイルすると、EXPORT_SYMBOLしているシンボルは、/usr/src/linux/Module.symversに書き出されます。

オリジナルなLKMのコンパイルも、カーネルがLKMをコンパイルするのとまったく同じで、通常はカーネルのMakefileへの橋渡するMakefileを通して行ったりします。そしてカーネルMakefileでは、scripts/Makefile.modpostへ橋渡ししています。この時CONFIG_MODVERSIONSが設定されていたら、オプション-mでmodpostを起動することになります。

modpostはmodpost.cから作成されていて、/usr/src/linux/Module.symversを参照することで、LKMで使用されているシンボルがカーネル内にあるかどうかをチェックします。

modpost -mで起動すると、LKMで使用しているシンボルにmodule_layout()を無理やり追加します。module_layout()は空の関数です。従ってCONFIG_MODVERSIONSが設定されていると、Module.symversにmodule_layoutが設定されていますが、そうでない故、module_layout" [/home/kitamura/lkm/euid.ko] undefined!とのメッセージが表示されるわけです。
#ifdef CONFIG_MODVERSIONS
void module_layout(struct module *mod,
                  struct modversion_info *ver,
                  struct kernel_param *kp,
                  struct kernel_symbol *ks,
                  struct tracepoint * const *tp)
{
}
EXPORT_SYMBOL(module_layout);
#endif
以前Kernel2でCONFIG_MODVERSIONSを調べていた時、MakefileにCONFIG_MODVERSIONSを設定してLKMをコンパイルしていました。現在セルフコンパイルしたKernel3にしており、前のCONFIG_MODVERSIONSを設定していたmakefileでLKMを作成したために表示されたようです。これもKernel3で追加された機能の1つでしょうが、ちょっと細かすぎはしないかと・・・。

通常、母艦のMakefileをそのまま使うので、このエラーメッセージが発生す事はないと思いますが、表示されるとマジック番号が違っている可能性があります。insmodできないようですと、マジック番号をチェックされたらいいかと思います。エラーメッセージのmodule_layoutとはまったく関係ありません。

scripts/Makefile.modpost
   :
modpost = scripts/mod/                    \
 $(if $(CONFIG_MODVERSIONS),-m)                  \
 $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,)       \
 $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile)   \
 $(if $(KBUILD_EXTMOD),-I $(modulesymfile))      \
 $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \
 $(if $(KBUILD_EXTMOD),-o $(modulesymfile))      \
 $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S)      \
 $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
 $(if $(cross_build),-c)
   :
modpost.cのmainです。-mオプションの時、modversions = 1とし、read_symbols()でモジュールで使われているカーネルシンボルを取得します。この時、modversions = 1ならalloc_symbol()でmodule_layoutを追加し、check_exports()でModule.symversとの照合を行います。
int main(int argc, char **argv)
{
       struct module *mod;
       struct buffer buf = { };
       char *kernel_read = NULL, *module_read = NULL;
       char *dump_write = NULL;
       int opt;
       int err;
       struct ext_sym_list *extsym_iter;
       struct ext_sym_list *extsym_start = NULL;

       while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) {
               switch (opt) {
 :
               case 'e':
                       external_module = 1;
                       extsym_iter =
                          NOFAIL(malloc(sizeof(*extsym_iter)));
                       extsym_iter->next = extsym_start;
                       extsym_iter->file = optarg;
                       extsym_start = extsym_iter;
                       break;
               case 'm':
                       modversions = 1;
                       break;
               case 'o':
                       dump_write = optarg;
                       break;
 : 
             default:
                       exit(1);
               }
       }

       if (kernel_read)
               read_dump(kernel_read, 1);
       if (module_read)
               read_dump(module_read, 0);
       while (extsym_start) {
               read_dump(extsym_start->file, 0);
               extsym_iter = extsym_start->next;
               free(extsym_start);
               extsym_start = extsym_iter;
       }

       while (optind < argc)
               read_symbols(argv[optind++]);

       for (mod = modules; mod; mod = mod->next) {
               if (mod->skip)
                       continue;
               check_exports(mod);
       }
 :
       return err;
}

static void read_symbols(char *modname)
{
       const char *symname;
       char *version;
       char *license;
       struct module *mod;
       struct elf_info info = { };
       Elf_Sym *sym;
  :
       version = get_modinfo(info.modinfo, info.modinfo_len, "version");
       if (version)
               maybe_frob_rcs_version(modname, version, info.modinfo,
                                      version - (char *)info.hdr);
       if (version || (all_versions && !is_vmlinux(modname)))
               get_src_version(modname, mod->srcversion,
                               sizeof(mod->srcversion)-1);

       parse_elf_finish(&info);

       if (modversions)
               mod->unres = alloc_symbol("module_layout", 0, mod->unres);
}
カーネルがCONFIG_MODVERSIONSでコンパイルされているかどうかは、/usr/src/linux/Module.symversにmodule_layoutの有無を調べることが可能でもあるわけです。

最終更新 2013/11/07 01:32:26 - north
(2013/11/06 15:02:33 作成)


検索

アクセス数
3585927
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。