load_binary 手続き

v3.7-rc7 くらいの linux-next の中を確認してみたところ、以下な出力。

$ find -name "*.[ch]"|xargs grep load_binary
./include/linux/binfmts.h:      int (*load_binary)(struct linux_binprm *);
./fs/binfmt_flat.c:     .load_binary    = load_flat_binary,
./fs/binfmt_em86.c:     .load_binary    = load_em86,
./fs/binfmt_elf.c:      .load_binary    = load_elf_binary,
./fs/binfmt_aout.c:     .load_binary    = load_aout_binary,
./fs/binfmt_misc.c:     .load_binary = load_misc_binary,
./fs/exec.c:    /* Need to fetch pid before load_binary changes it */
./fs/exec.c:                    int (*fn)(struct linux_binprm *) = fmt->load_binary;
./fs/binfmt_elf_fdpic.c:        .load_binary    = load_elf_fdpic_binary,
./fs/binfmt_script.c:   .load_binary    = load_script,
./fs/binfmt_som.c:      .load_binary    = load_som_binary,
./arch/alpha/kernel/binfmt_loader.c:static int load_binary(struct linux_binprm *bprm)
./arch/alpha/kernel/binfmt_loader.c:    .load_binary    = load_binary,
./arch/x86/ia32/ia32_aout.c:    .load_binary    = load_aout_binary,
./drivers/staging/wlags49_h2/wl_main.c:                                 DBG_TRACE( DbgInfo, "before dhf_download_binary\n" );
./drivers/staging/wlags49_h2/wl_main.c:                                 hcf_status = dhf_download_binary( (memimage *)cp );
./drivers/staging/wlags49_h2/wl_main.c:                                 DBG_TRACE( DbgInfo, "after dhf_download_binary, before dhf_download_fw\n" );
./drivers/staging/wlags49_h2/dhf.c:*.MODULE             int dhf_download_binary( void *ifbp, memimage *fw )
./drivers/staging/wlags49_h2/dhf.c:     MMDASSERT is unacceptable because some drivers call dhf_download_binary before hcf_connect
./drivers/staging/wlags49_h2/dhf.c:dhf_download_binary(memimage *fw)
./drivers/staging/wlags49_h2/dhf.c:}   /* dhf_download_binary */
./drivers/staging/wlags49_h2/dhf.h:EXTERN_C int dhf_download_binary(memimage *fw);
$

やはり微妙なのは fs/exec.c と見て中身を確認。
呼び出してるのはこのあたり (search_binary_handler 手続き) なのか。

	retval = -ENOENT;
	for (try=0; try<2; try++) {
		read_lock(&binfmt_lock);
		list_for_each_entry(fmt, &formats, lh) {
			int (*fn)(struct linux_binprm *) = fmt->load_binary;
			if (!fn)
				continue;
			if (!try_module_get(fmt->module))
				continue;
			read_unlock(&binfmt_lock);
			bprm->recursion_depth = depth + 1;
			retval = fn(bprm);

ええと、fs/binfmt_elf.c の中見てみるに以下な定義がありますね。

static struct linux_binfmt elf_format = {
	.module		= THIS_MODULE,
	.load_binary	= load_elf_binary,
	.load_shlib	= load_elf_library,
	.core_dump	= elf_core_dump,
	.min_coredump	= ELF_EXEC_PAGESIZE,
};

で、load_elf_binary が核心なのか。

とその前に

この search_binary_handler の呼び出し元も見てみたいです。

$ find -name "*.[ch]"|xargs grep search_binary_handler
./include/linux/binfmts.h:extern int search_binary_handler(struct linux_binprm *);
./fs/binfmt_em86.c:     return search_binary_handler(bprm);
./fs/binfmt_misc.c:     retval = search_binary_handler(bprm);
./fs/exec.c:int search_binary_handler(struct linux_binprm *bprm)
./fs/exec.c:EXPORT_SYMBOL(search_binary_handler);
./fs/exec.c:    retval = search_binary_handler(bprm);
./fs/binfmt_script.c:   return search_binary_handler(bprm);
./arch/alpha/kernel/binfmt_loader.c:    return search_binary_handler(bprm);
$

いくつか直接呼び出しているように見えますが、本線は fs/exec.c の do_execve_common 手続き (上の出力で呼び出している箇所) なようです。do_execve_common で struct linux_binprm なオブジェクトの用意をしている模様。

load_elf_binary 手続きに戻って

ええと処理手順としては以下みたいです。

  • ELF インタプリタを読み込み
  • flush_old_exec 手続きは fork した情報を exec するソレに書き換えとのこと
    • プログラムヘッダの LOAD な部分をメモリに展開
  • load_elf_interp 手続きは ELF インタプリタをメモリに展開する手続き
  • start_thread 手続きが kickoff するのは ELF インタプリタ
    • elf_entry (ELF ヘッダの Entry point address) は ELF インタプリタの実行開始アドレス

ELF バイナリのエントリ突入してから以降も色々確認してみたくはありますが、あまりにも道長き道です。