shell会执行evecve()进行系统调用,如下所示

execve -> sys_execve -> do_execve -> do_execveat_common -> exec_binprm -> search_binary_handler

do_execveat_common函数中,主要需要分析的位置在:

retval = exec_binprm(bprm);
if (retval < 0)
    goto out;

exec_binprm函数中,主要需要分析的位置在:

rcu_read_lock();
old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
rcu_read_unlock();

ret = search_binary_handler(bprm);

search_binary_handler函数中,主要需要分析的位置在:

read_lock(&binfmt_lock);
list_for_each_entry(fmt, &formats, lh) {
    if (!try_module_get(fmt->module))
        continue;
    read_unlock(&binfmt_lock);
    bprm->recursion_depth++;
    retval = fmt->load_binary(bprm);
    read_lock(&binfmt_lock);
    put_binfmt(fmt);
    bprm->recursion_depth--;
    if (retval < 0 && !bprm->mm) {
        /* we got to flush_old_exec() and failed after it */
        read_unlock(&binfmt_lock);
        force_sigsegv(SIGSEGV, current);
        return retval;
    }
    if (retval != -ENOEXEC || !bprm->file) {
        read_unlock(&binfmt_lock);
        return retval;
    }
}
read_unlock(&binfmt_lock);

分析:

search_binary_handle()遍历formats链表(所有注册的二进制格式),依次尝试二进制格式的load_binary().

这段代码 retval = fmt->load_binary(bprm); 的意思是从对应的二进制格式变量中使用load_binary调用对应的加载函数。对应于elf文件,这个函数指针指向load_elf_binary(),具体内容可以参见Linux内核中ELF加载解析(二)