可执行程序的装载过程

Posted on 2016-04-10 21:42  昆仑雪狐  阅读(394)  评论(0编辑  收藏  举报

 可执行文件的创建--预处理、编译和链接的过程

生成预处理文件
gcc -E -o hello.cpp hello.c -m32    
生成汇编文件
gcc  -x cpp-output -S -o  hello.s hello.cpp -m32
生成目标文件
gcc -x assembler -c  hello.s -o hello.o -m32
生成可执行文件
gcc -o hello hello.o -m32
生成带静态库的可执行文件
gcc -o hello.static hello.o -m32 -static
查看ELF文件的头部
readelf -h hello
查看ELF文件依赖的共享库
ldd main
ldd xxx
shell调用execve将命令行参数和环境参数传给可执行程序的main函数
int execve(const char *filename,char * const argv[ ],char * const envp[ ] );
库函数exec*都是execve的封装例程。
 
在系统界面输入exec,系统程序运行至sys_execve断点处,开始按步跟踪。
在start_thread处输入po new_ip命令:
使用readelf命令查看elf文件hello的入口地址: 
到此,可执行文件的加载运行流程就跟踪完毕了,接下来根据具体函数实现简要分析函数的功能与执行流程:
execve( ) :
SYSCALL_DEFINE3(execve,
        const char __user *, filename,
        const char __user *const __user *, argv,
        const char __user *const __user *, envp)
{
    return do_execve(getname(filename), argv, envp);
}
在此处调用getname(filename),getname函数实现如下:
getname(const char __user * filename)
{
    return getname_flags(filename, 0, NULL);
}
功能是将要执行的文件名字符串从用户空间拷贝到系统空间,会首先调用getname_flags( ):
static struct filename *
getname_flags(const char __user *filename, int flags, int *empty)
{
    struct filename *result, *err;
    int len;
    long max;
    char *kname;
 
    result = audit_reusename(filename);
    if (result)
        return result;
 
    result = __getname();
    if (unlikely(!result))
        return ERR_PTR(-ENOMEM);
 
    /*
     * First, try to embed the struct filename inside the names_cache
     * allocation
     */
    kname = (char *)result + sizeof(*result);
    result->name = kname;
    result->separate = false;
    max = EMBEDDED_NAME_MAX;
 
recopy:
    len = strncpy_from_user(kname, filename, max);
    if (unlikely(len < 0)) {
        err = ERR_PTR(len);
        goto error;
    }
 
    /*
     * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
     * separate struct filename so we can dedicate the entire
     * names_cache allocation for the pathname, and re-do the copy from
     * userland.
     */
    if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) {
        kname = (char *)result;
 
        result = kzalloc(sizeof(*result), GFP_KERNEL);
        if (!result) {
            err = ERR_PTR(-ENOMEM);
            result = (struct filename *)kname;
            goto error;
        }
        result->name = kname;
        result->separate = true;
        max = PATH_MAX;
        goto recopy;
    }
 
    /* The empty path is special. */
    if (unlikely(!len)) {
        if (empty)
            *empty = 1;
        err = ERR_PTR(-ENOENT);
        if (!(flags & LOOKUP_EMPTY))
            goto error;
    }
 
    err = ERR_PTR(-ENAMETOOLONG);
    if (unlikely(len >= PATH_MAX))
        goto error;
 
    result->uptr = filename;
    result->aname = NULL;
    audit_getname(result);
    return result;
 
error:
    final_putname(result);
    return err;
}
getname_flags通过__getname()为文件名分配一个物理页面储存文件的绝对路径。因为绝对路径可能很长,但系统堆栈只有7kB空间。

By:昆仑雪狐

原创作品转载请注明出处

《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000