系统相关
首页 > 系统相关> > Linux内核装载ELF过程简介

Linux内核装载ELF过程简介

作者:互联网

目录

Linux内核装载ELF过程简介

用户层:

用户层bash进程会调用fork系统调用创建一个新的进程,然后新的进程调用execve()系统调用执行指定的ELF文件,原先的bash进程继续返回等待刚才启动的新进程结束,然后继续等待用户输入命令。

扩展学习:https://blog.csdn.net/qq_41453285/article/details/89006116

int execve(const char *filename,char *const argv[], char *const envp[]);

//filename  = 被执行的程序文件名
//argv[]    = 执行的参数
//envp[]    = 环境变量

利用fork()、execlp()实现minibash:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    char buf[1024]={0};
    pid_t pid;
    while(1)
    {
        printf("minibash$");
        scanf("%s",buf);
        pid = fork();
        if(pid == 0)//子进程
        {
            if(execlp(buf,0) < 0){
                printf("exec error\n");
            }
        }else if(pid > 0)//父进程
        {
            int status;
            waitpid(pid,&status,0);//等待子进程返回
            printf("子进程执行完毕!\n");
        }else{
            //返回-1 创建进程失败!
            printf("创建进程失败!\n");
        }
    }
    return 0;
}

内核层

在用户层调用execve函数后,进入到内核层,Linux内核开始进行真正的装载工作。

execve() 系统调用相应的入口是sys_execve(),在源码arch\i386\kernel\Process.c中被定义。

最终sys_execve会调用do_execve()函数,do_execve函数会首先查找被执行的文件,如果找到文件,读取文件的前128字节,用来判断文件Magic(魔数)

确定是ELF文件后,最后会调用load_elf_binary()函数来进行ELF文件的装载,该文件被定义在fs\Binfmt_elf.c中。(函数的主要实现步骤):

(1) 检查ELF可执行文件格式的有效性,比如Magic(魔数)、程序头表(段表)的数量。
(2) 寻找动态链接的 ".interp"段,设置动态链接器的路径。
(3) 根据ELF可执行文件的程序头表(段表),对ELF文件进行映射,代码段、数据段、只读数据段。
(4) 初始化ELF进程环境,比如进程启动时EDX寄存器的地址应该是"DT_FINI"地址。
(5) 将系统调用的返回地址修改成"ELF可执行文件入口点",(如果是静态链接,那么入口点是"e_entry"),(如果是动态链接,那么入口点是"动态链接器")
(6) laod_elf_binary() ret -> do_execve() ret -> sys_execve() ret[返回已被修改] -> eip =(ELF入口) 开始执行ELF程序,装载完毕,进程执行。

标签:调用,pid,ELF,内核,Linux,进程,execve
来源: https://www.cnblogs.com/VxerLee/p/16365610.html