0%

程序员自我修养读后感(4)-可执行文件加载

可执行文件的装载与运行

虚拟地址空间

程序通过编译链接之后,各个变量及函数的虚拟地址就已经确定了。每个程序都拥有独立的内存空间,程序运行时使用的是虚拟地址,操作系统通过内存映射的方式,把虚拟地址映射到物理地址,程序只需要通过虚拟地址操作即可,不需要关心实际的物理内存地址。程序可访问的虚拟地址的大小与系统的总线位宽相关, 32位系统允许访问4GB的地址。操作系统通过页映射的方式,加载程序的数据和指令到内存,没有被使用的数据和指令就被替换到磁盘中。

文件的装载

进程创建时,操作系统首先创建一个独立的虚拟地址空间,并建立一个页目录结构,用于后面保存页与物理地址的映射关系。然后读取可执行文件的文件头,建立虚拟地址空间与执行文件的映射关系。
然后cpu指令寄存器设置为可执行文件的入口地址,启动运行。 CPU在运行的过程中,去访问对应的虚拟地址,会发现对应的页内容是空的,即发生了页错误,转而由系统分配物理内容,然后建立映射关系,加载数据与指令,再由程序继续运行。

可执行文件 – 虚拟地址空间 – 物理内存空间

虚拟地址空间的分配

由于页映射加载需要保证按页面大小对齐加载,那么每个段需要以页大小的倍数进行装载,不足一页也要占用一个页的大小,浪费了空间。系统通过合并多个相同属性的段进行加载。合并后的段,称为segment。

1
2
3
4
5
6
readelf -l exec_file // 可以显示具体的地址及段


查看实际执行的内存分布情况
cat /proc/{pid}/maps

Linux加载elf的简要步骤

  1. 读取文件的前面128字节, 判断文件类型
  2. 查找不同文件的handler函数
  3. 根据程序表头,对文件进行映射
  4. 初始化进程环境, 修改入口地址
  5. 开始执行

行动,才不会被动!

欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。