zoukankan      html  css  js  c++  java
  • 2019-2020-1 20199305《Linux内核原理与分析》第八周作业

    可执行程序的工作原理

    (一)ELF目标文件

    (1)什么是ELF?

    这里先提一个常见的名词“目标文件”,是指编译器生成的文件。ELF(Executable and Linkable Format),即可执行的和可链接的格式,是一个目标文件格式的标准,这种格式的文件用于存储Linux程序。

    (2)ELF文件的3种类型

    • 可重定位文件

    • 可执行文件

    • 共享目标文件

    (3)ELF文件的作用

    • 如果用于编译和链接,则编译器和链结器将把ELF文件看作节的集合,所有节由节头表描述,程序头表可选

    • 如果用于加载执行(可执行文件),则加载器将把ELF文件看作程序头表描述的段的集合,一个段可能包含又多个节和节头表可选

    • 如果是共享文件,则两者都含有

    (二)程序编译

    程序从源代码到可执行文件的步骤:预处理、编译、汇编、链接。

    • 预处理

    gcc -E hello.c -o hello.i

    • 编译

    gcc -S hello.i -o hello.s -m32

    • 汇编

    gcc -c hello.s -o hello.o -m32

    • 链接

    gcc hello.o -o hello -m32

    (三)Linux系统构架与执行过程

    (1)从内存角度看Linux系统的执行

    (2)fork和execve的区别与联系

    • fork两次返回,第一次返回到父进程继续向下执行,第二次是子进程返回到ret_from_fork后正常返回用户态

    • execve在执行时陷入内核态,用execve中加载的程序把当前正在执行的进程覆盖掉,当系统调用返回时也就返回到新的可执行程序起点,即返回的已经不是原来的那个可执行程序了

    (3)跟踪分析execve系统调用内核处理函数

    1)将menu目录删除,利用git命令克隆一个新的menu目录,用test_exec.c将test.c覆盖

    2)重新编译rootfs,查看代码发现增加了exec函数,执行exec指令,发现比fork指令多输出了一行“hello,Yizihan”,实际上是新加载了一个可执行程序来输出一行语句



    3)启动内核到调试的状态,加载符号表并设置端口,启动新的终端窗口开始gdb调试,设置断点到“sys_exec” “load_elf_binary” “start_thread”




    4)查看hello的elf的头部,查看定义的入口地址

    5)实验中test.c中增加的代码如下:

    int Exec(int argc, char *argv[])
    {
        int pid;
        /* fork another process */
        pid = fork();
        if (pid < 0) 
        { 
            /* error occurred */
            fprintf(stderr,"Fork Failed!");
            exit(-1);
        } 
        else if (pid == 0) 
        {
            /*   child process  */
            printf("This is Child Process!
    ");
            execlp("/hello","hello",NULL);
        } 
        else 
        {   
            /*  parent process   */
            printf("This is Parent Process!
    ");
            /* parent will wait for the child to complete*/
            wait(NULL);
            printf("Child Complete!
    ");
        }
    }
    
    int main()
    {
        PrintMenuOS();
        SetPrompt("MenuOS>>");
        MenuConfig("version","MenuOS V1.0(Based on Linux 3.18.6)",NULL);
        MenuConfig("quit","Quit from MenuOS",Quit);
        MenuConfig("time","Show System Time",Time);
        MenuConfig("time-asm","Show System Time(asm)",TimeAsm);
        MenuConfig("fork","Fork a new process",Fork);
        MenuConfig("exec","Execute a program",Exec);
        ExecuteMenu();
    }
    

    (四)总结

    execve()的系统调用实质试运行的内核态的函数,大致处理过程总结如下:

    (1)sys_execve中的do_execve()读取128个字节的文件头部,以此判断可执行文件的类型

    (2)调用search_binary_handle()去搜索和匹配合适的可执行文件转载处理过程

    (3)ELF文件由load_elf_binary()函数负责装载,它调用了sart_thread函数,创建新进程的堆栈,修改了终端现场中保存的ELP寄存器,这里分静态链接和动态链接两种:

    • 静态链接:elf_entry指向可执行文件的头部,一般是main函数,是新程序执行的起点,,新的可执行程序的起点的一般地址为0x8048xxx的位置,由编译器设定,可能是由于安全上的考虑并不严格固定

    • 动态链接:elf_entry指向ld(动态链接器)的起点load_elf_interrp

  • 相关阅读:
    vue组件的通信
    vue基础
    vue项目总结
    路由(4)传参
    路由(3)
    第一次作业
    JAVA-2.0-homework
    JAVA-2.0-上机
    JAVA-1.9-homework
    JAVA-1.9-上机
  • 原文地址:https://www.cnblogs.com/20199305yizihan/p/11816267.html
Copyright © 2011-2022 走看看