读书-程序员的自我修养-链接、封装与库(16: 第六章:可执行文件的装载与进程(4)Linux 内核装载ELF过程简介 和 windows PE的装载

读书-程序员的自我修养-链接、封装与库(16: 第六章:可执行文件的装载与进程(4)Linux 内核装载ELF过程简介 和 windows PE的装载)

1. Linux 内核装载ELF过程简介

当我们在linux系统的bash下输入一个命令执行某个elf程序时,
linux系统是怎么装载这个elf文件并执行它的呢?
我们以helloworld为例子 a.out

1.1 ./a.out 背后的逻辑

  1. 首先,bash 进程会调用 fork() 系统调用创建一个新的进程,假设叫做hello进程

  2. 新的进程(hello进程)调用 execve() 系统调用执行 a.out

    2.1 execve 有三个参数:程序文件名 执行参数 环境变量
    其中, Glibc 对 execve 系统调用进程了包装,提供了 execl execp execle execv execvp这五种APOI
    它们只是调用参数有区别,最终都会调用 execve.

    2.2 进入 execve linux内核才开始真正的装载工作。

    2.3 execve -> sys_execve -> do_execve
    do_execve 读取可执行文件 a.out 的前128字节判断文件格式
    因为前128字节标识了文件类型:elf java windows的pe 等可执行文件格式
    每个可执行文件的前4字节很特殊,称为魔数字表明格式和类型,如ELF的是 0x7f e l f
    java的可执行文件前4字节是: c a f e,shell python脚本前面是 #!/bin/sh等

    2.4 do_execve -> search_binary_handle 这个搜索和匹配合适的可执行文件装载处理过程。

    2.5 然后调用 load_elf_binary 它装载可执行文件 a.out ,具体包括以下步骤:
    第一,检查可执行文件格式的有效性
    第二,寻找动态链接的 ”.interp" 段,设置动态链接器路径
    第三,根据elf文件的程序头标描述,对elf文件进行映射
    第四,初始化elf进程环境
    第五,将系统调用的返回地址修改成elf 可执行文件的入口点,这里就是 a.out 的 main

    2.6 ELF a.out 开始执行,elf 可执行文件装载完成

  3. 原先的bash进程继续返回等待这个进程结束,然后继续等待用户输入命令

2. windows PE的装载

2.1 PE 和 ELF 有所不同

PE 文件的所有段的起始地址都是页的倍数
这样映射就简单多了 没有所谓的 segment 了,但是会浪费一点内存磁盘和内存空间

2.2 RAV 相对虚拟地址 基地址

RAV 相对虚拟地址: 就是地址偏移
基地址: 文件的装载目标地址就是基地址

猜你喜欢

转载自blog.csdn.net/lqy971966/article/details/107050334