可执行文件的装载与运行
虚拟地址空间
程序通过编译链接之后,各个变量及函数的虚拟地址就已经确定了。每个程序都拥有独立的内存空间,程序运行时使用的是虚拟地址,操作系统通过内存映射的方式,把虚拟地址映射到物理地址,程序只需要通过虚拟地址操作即可,不需要关心实际的物理内存地址。程序可访问的虚拟地址的大小与系统的总线位宽相关, 32位系统允许访问4GB的地址。操作系统通过页映射的方式,加载程序的数据和指令到内存,没有被使用的数据和指令就被替换到磁盘中。
文件的装载
进程创建时,操作系统首先创建一个独立的虚拟地址空间,并建立一个页目录结构,用于后面保存页与物理地址的映射关系。然后读取可执行文件的文件头,建立虚拟地址空间与执行文件的映射关系。
然后cpu指令寄存器设置为可执行文件的入口地址,启动运行。 CPU在运行的过程中,去访问对应的虚拟地址,会发现对应的页内容是空的,即发生了页错误,转而由系统分配物理内容,然后建立映射关系,加载数据与指令,再由程序继续运行。
可执行文件 – 虚拟地址空间 – 物理内存空间
虚拟地址空间的分配
由于页映射加载需要保证按页面大小对齐加载,那么每个段需要以页大小的倍数进行装载,不足一页也要占用一个页的大小,浪费了空间。系统通过合并多个相同属性的段进行加载。合并后的段,称为segment。
1 | readelf -l exec_file // 可以显示具体的地址及段 |
Linux加载elf的简要步骤
- 读取文件的前面128字节, 判断文件类型
- 查找不同文件的handler函数
- 根据程序表头,对文件进行映射
- 初始化进程环境, 修改入口地址
- 开始执行
行动,才不会被动!
欢迎关注个人公众号 微信 -> 搜索 -> fishmwei,沟通交流。