無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

lkm起動について


FLATフォーマットの動作テストをしようと、nasmでFLATバイナリを作成し実行すると、バイナリファイルを実行できません。のメッセージが表示されました。binfmt_flatのモジュールがinsmodされてないんだろう。とlsmodすると、
[root@localhost kitamura]# lsmod | grep binfmt
binfmt_misc            17207  1
binfmt_miscしか表示されていません。(wineをインストールした時に、勝手にインストールされました。)。確かにbinfmt_flatが組み込まれていません。でも、「なんでbinfmt_elfがインストールされてないの。」

下記はmodule_initマクロ(hogehoge.c)が、どのように展開されるか見たものです。module_initマクロは、__inittest()とinit_module()の2つの関数を定義し、__inittest()は定義した関数アドレスを、init_module()は定義した関数(aliasで設定)となります。そして、__inittest()はinitcall_tで宣言して、.text.initセクションに配置されます。従って.text.initセクションに設定されているアドレスをコールした返り値をコールする事で、モジュールのinit()がコールされる事になります。
(と読み取れるのですが、 do_initcalls()の実装を見ると、.text.initセクションには初期関数(hogehoge)のアドレスが設定されているやにも見受けられるのですが・・・)
[root@localhost test]# cat hogehoge.c
typedef int (*initcall_t)(void);
#define __init __attribute__ ((__section__ (".text.init")))

#define module_init(initfn)                                     \
       static inline initcall_t __inittest(void)               \
       { return initfn; }                                      \
       int init_module(void) __attribute__((alias(#initfn)));

static int __init hogehoge(void)
{
}

module_init(hogehoge)

[root@localhost test]# gcc -E hogehoge.c
# 1 "hogehoge.c"
# 1 "<組み込み>"
# 1 "<コマンドライン>"
# 1 "hogehoge.c"
typedef int (*initcall_t)(void);
# 10 "hogehoge.c"
static int __attribute__ ((__section__ (".text.init"))) hogehoge(void)
{
}

static inline initcall_t __inittest(void) { return hogehoge; } int init_module(void) __attribute__((alias("hogehoge")));
insmodすると、システムコールsys_init_moduleがコールされ、load_module()をコールする事で、lkmをロード/実行します。そしてstruct module *modをlist_add(&mod->list, &modules)で、modulesにリストします。このリスト化がlsmodコマンドの表示対象となるわけです。従って、sys_init_module()を介さないでモジュールをロードすると、lsmodで表示されない事になります。(他にmodulesにリストしている処理は、ありませんでした。)
#define __NR_init_module                       175
__SYSCALL(__NR_init_module, sys_init_module)

asmlinkage long sys_init_module(void __user *umod,
               unsigned long len,
               const char __user *uargs)
{
       struct module *mod;
       int ret;

       if (!capable(CAP_SYS_MODULE))
               return -EPERM;

       if (down_interruptible(&module_mutex) != 0)
               return -EINTR;

       mod = load_module(umod, len, uargs);
       if (IS_ERR(mod)) {
               up(&module_mutex);
               return PTR_ERR(mod);
       }

       if (mod->module_init)
               flush_icache_range((unsigned long)mod->module_init,
                                  (unsigned long)mod->module_init
                                  + mod->init_size);
       flush_icache_range((unsigned long)mod->module_core,
                          (unsigned long)mod->module_core + mod->core_size);

       spin_lock_irq(&modlist_lock);
       list_add(&mod->list, &modules);
       spin_unlock_irq(&modlist_lock);
  :
}
binfmt_elfのケースだと、カーネルコンパイル時にローダブルモジュールとするか、カーネルその物にバンドリングするかの設定があるやに思います。(このような事意識してコンパイルした事なかったので、定かではありません。)で、binfmt_elfはカーネル本体の一部として組み込まれ、この.text.initセクションに、初期化関数のアドレスが配置されるわけです。

start_kernael()で低レベル実行環境が整った後、最後にinit()がコールされます。そこのdo_basic_setup()/ do_initcalls()で、__initcall_start/__initcall_endは、.text.initセクションの開始/終了アドレス(たぶん)で、その中のアドレスを順にコールする事で、binfmt_elf等の起動が行われるようです。
static void __init do_basic_setup(void)
{
       driver_init();

#ifdef CONFIG_SYSCTL
       sysctl_init();
#endif

       sock_init();

       init_workqueues();
       do_initcalls();
}

static void __init do_initcalls(void)
{
       initcall_t *call;
       int count = preempt_count();

       for (call = &__initcall_start; call < &__initcall_end; call++) {
               char *msg;

               if (initcall_debug)
                       printk("calling initcall 0x%p\n", *call);

               (*call)();

               msg = NULL;
               if (preempt_count() != count) {
                       msg = "preemption imbalance";
                       preempt_count() = count;
               }
               if (irqs_disabled()) {
                       msg = "disabled interrupts";
                       local_irq_enable();
               }
               if (msg) {
                       printk("error in initcall at 0x%p: "
                               "returned with %s\n", *call, msg);
               }
       }

        flush_scheduled_work();
}

追記

make menuconfigで、<*>又は<M>で、built-inとするかmoduleとするかの設定を行っていました。また、カーネルver3.3.8ですが、ソースとしてbinfmt_flat.cは有るのですが、make menuconfigのecutable file formats / Emulationsセクションにflatの項目がありませんでした。独自にbinfmt_flat.cだけをモジュールとしてコンパイルしてみましたが、エラーで出て疲れがどどっど。って感じです。

最終更新 2013/05/15 19:24:13 - north
(2013/05/07 20:43:52 作成)