Linux环境下:程序的链接, 装载和库[可执行文件的装载]

现代操作系统如何装载可执行文件?

  • 给进程分配独立的虚拟地址空间
  • 建立虚拟地址空间和可执行文件的映射关系
  • 把CPU指令寄存器设置成可执行文件的入口地址,启动执行

可执行文件在装载的过程中实际上是映射的虚拟地址空间,所以可执行文件通常被叫做映像文件(或者Image文件).

ELF文件的两种视角

  • Section header table: 编译器、汇编器和链接器将这个文件看作是被区段(section)头部表描述的一系列逻辑区段的集合
  • Program header table: 系统加载器将文件看成是由程序头部表描述的一系列段(segment)的集合。一个段(segment)通常会由多个区段(section)组成。例如,一个“可加载只读”段可以由可执行代码区段、只读数据区段和动态链接器需要的符号组成

image.png
readelf -a 可执行文件 可以看到section和segment的映射关系

readelf -a sta_loop
image.png
每个Segment包含的Section在下面的mapping种可以看到。图中Program Headers的Type的含义可以在 /usr/include/elf.h 中查看,Load即表示可装载的段
image.png

可以单独通过 readelf -l sta_loop查看可执行文件的程序头
-l --program-headers Display the program headers

ELF可执行文件和进程虚拟地址空间的映射关系

样例

#include <stdlib.h>

int main()
{
    void* pm = NULL;

    for(;;)
    {
       pm = malloc(100);
       sleep(500);
       if(pm)
       {
           free(pm);
       }
    }
}

编译成静态链接库 sta_loop
执行 ./sta_loop &
通过 proc 文件系统 /proc/<PID>/maps查看虚拟内存的映射情况, 该文件有6列, 各个列的含义

  • 地址:虚拟内存区域的起始和终止地址
  • 权限:虚拟内存的权限,r=读,w=写,x=执行,s=共享,p=私有
  • 偏移量:虚拟内存区域在被映射文件中的偏移量
  • 设备:映像文件的主设备号和次设备号
  • 节点:映像文件的节点号
  • 路径: 映像文件的路径

image.png
这里可以看到上面的两个段都对应到我们的静态链接库的elf文件,分别是只读+可执行的段以及可读可写的段。可以看到第二段的offset是映像文件中的偏移,000a6000和上面readelf -a sta_loop看到的偏移一致。

这个就是对应在操作系统中学到的,执行一个程序首先是要将可执行文件加载到可执行的代码段和数据段
image.png

具体linux内核是如何加载可执行程序并进行虚拟内存映射的可以查看这篇文章
https://blog.csdn.net/gatieme/article/details/51628257

posted @ 2023-02-05 13:34  Aitozi  阅读(155)  评论(0编辑  收藏  举报