zoukankan      html  css  js  c++  java
  • 可执行程序的装载

    1.预处理、编译、链接和目标文件的格式

    1.1可执行程序的来源

    1.1.1一个简单的流程

    image

    .c(省略了预处理)汇编成汇编汇编代码asm,然后汇编成目标码.o,在链接成可执行文件,可执行文件加载到内存执行。

    1.1.2用hello.c做简单的实验

    #include <stdio.h>
    int main()
    {
        printf("hello");
        return 0;
    }
    #预处理,hello.cpp为预处理的中间文件
    #预处理负责把include的文件包含进来以及宏替换等工作
    gcc -E -o hello.cpp hello.c -m32    
    #预处理后的文件编译成汇编代码
    gcc -x cpp-output -S -o hello.s hello.cpp -m32
    #将汇编代码hello.s编译成目标代码,得到二进制的hello.o文件
    gcc -x assembler -c hello.s -o hello.o -m32
    #hello.o链接成可执行文件
    gcc -o hello hello.o -m32
    #hello可执行文件使用共享库
    #静态编译出的hello.static是把所有需要执行的依赖的东西放在程序内部,因此会比hello大 
    gcc -o hello.static hello.o -m32 -static

    1.2目标文件的格式elf(executable and linkable format)

    elf格式文件中三种主要的目标文件

    • 可重定位文件,保存着代码和适当的数据,用来和其他的object文件一起创建一个可执行文件或一个共享文件(主要是.o文件)
    • 可执行文件,保存一个用来执行的程序,该文件指出了exec(系统调用)如何创建程序进程映像
    • 共享object文件,保存着代码和合适的数据,用来被链接器(链接编译器、动态链接器)链接(主要是.so文件)

    2 可执行程序、共享库和动态链接

    ,是一种封装机制,简单说是把所有的源代码编译成目标代码后打成的包。库的开发者除了提供库的目标代码外,还提供一系列的头文件,头文件中就包含了库的接口,库分为静态库(static library)和共享库(share library)。在Linux中静态库以一种存档(archive)的特殊文件格式存放在磁盘中,由后缀.a标识;共享库通常用.so后缀来表示。win下分别是.lib和.dll。

    通常情况下,对函数库的链接是放在编译时期(compile time)完成的。所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执行文件(executable file)。程序在运行时,与函数库再无瓜葛,因为所有需要的函数已拷贝到自己门下。所以这些函数库被成为静态库(static libaray),通常文件名为“libxxx.a”的形式。其实,我们也可以把对一些库函数的链接载入推迟到程序运行时期(runtime)。这就是动态链接库(dynamic link library)技术,动态链接库的名字形式为 “libxxx.so” 后缀名为 “.so”

    3. 可执行程序的装载——可执行程序的装载相关关键问题分析

    可执行程序的装载也是系统调用,其中execve系统调用内核处理过程比较特殊,正常的系统调用陷入到内核态在返回到用户态,继续执行系统调用下一条指令。

    3.1 execve特殊之处

    当前可执行程序执行到execve这个系统调用时,陷入到内核态,在内核态里用execve加载的可执行文件把当前进程的可执行程序覆盖掉,当execve这个系统调用返回时,已经不是原来那个可执行程序,而是新的可执行程序。

    3.2 简单分析execve

    Shell会调用execve将命令行参数和环境参数传递给可执行程序的main函数

    • int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
    • 库函数exec*都是execve的封装例程

    当系统调用陷入到内核时,sys_call调用sys_execve,sys_execve内部会解析可执行文件格式

    • 调用顺序:do_execve -> do_execve_common –>  exec_binprm
    • 再,search_binary_handle符合寻找文件格式对应的解析模块
      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);
    • 对于ELF格式的可执行文件fmt->load_binary(bprm);执行的应该是load_elf_binary,其内部是和ELF文件格式解析的部分需要和ELF文件格式标准结合起来阅读。

    3.3 linux内核如何支持多种不同可执行文件格式

    //查看load_elf_binary对应的模块
    static struct linux_binfmt elf_format = {
      .module     = THIS_MODULE,
      //elf_format变量声明时,把load_elf_binary赋值给.load_binary这个函数指针
      .load_binary    = load_elf_binary,    
      .load_shlib = load_elf_library,
      .core_dump  = elf_core_dump,
      .min_coredump   = ELF_EXEC_PAGESIZE,
    };
    
    
    static int __init init_elf_binfmt(void)
    {
        //将elf_format注册进了内核链表中
        register_binfmt(&elf_format);
        return 0;
    }

    elf_format和init_elf_binfmt就是观察者模式的观察者。当出现elf文件格式时,观察者就会自动执行load_elf_binary。

    上述只是解析elf的部分代码,此外还要完成下面关键步骤

    在load_elf_binary中有个start_thread

    //修改了pt_regs,pt_regs是内核堆栈的栈底,当发生中断时,将ip,sp压栈。
    //当执行一个新进程时,需要将起点替换
    void start_thread(struct pt_regs *regs, unsigned long new_ip, unsigned long new_sp)
    {
        set_user_gs(regs, 0);
        regs->fs        = 0;
        regs->ds        = __USER_DS;
        regs->es        = __USER_DS;
        regs->ss        = __USER_DS;
        regs->cs        = __USER_CS;
        regs->ip        = new_ip;
        regs->sp        = new_sp;
        regs->flags        = X86_EFLAGS_IF;
        /*
         * force it to the iret return path by making it look as if there was
         * some work pending.
         */
        set_thread_flag(TIF_NOTIFY_RESUME);
    }
  • 相关阅读:
    ural1238. Folding(记忆化)
    URAL1410. Crack
    树套树Day1线段树套平衡树bzoj3196
    noipd2t3列队
    NOIP2017D1T3
    uoj279温暖会指引我们前行
    一篇打脸文
    Link-Cut Tree
    重口味费用流
    bzoj1000~1025
  • 原文地址:https://www.cnblogs.com/boyiliushui/p/5488285.html
Copyright © 2011-2022 走看看