ELF 静态链接和加载

ELF 静态链接和加载

2024 南京大学《操作系统:设计与实现》
ELF 静态链接和加载

有了 FLE,为什么还要 ELF?

如果你想构建 Chrome (2017)

  • 2 GiB binary (with debug info)
  • 17,000 files
  • 1,800,000 sections
  • 6,300,000 symbols
  • 13,000,000 relocations
    • C++ name mangling: _ZNK8KxVectorI6DlTypejEixEj is KxVector<DlType, unsigned int>::operator[](unsigned int) const
    • (看起来不用指针的确不行)
2024 南京大学《操作系统:设计与实现》
ELF 静态链接和加载

ELF 的链接

在 FLE 的基础上做加法: readelf -a 能看懂了!😀

  • Sections: 更多的节;更多的 flags
  [Nr] Name      Type      Address              Offset
       Size      EntSize   Flags  Link  Info     Align
  [ 5] .tdata    PROGBITS  00000000000000000  0000005c
       00000004  00000000  WAT       0     0         4
  • Relocations: 差不多;功能更丰富
  Offset          Info           Type        Name + Addend
000000000007  000500000016 R_X86_64_GOTTPOFF x - 4
000000000013  000600000017 R_X86_64_TPOFF32  y + 0
  • extern __thread int x; __thread int y;
2024 南京大学《操作系统:设计与实现》
ELF 静态链接和加载

加载:ELF v.s. FLE

FLE 加载器:只做一件事

  • 将一段字节序列复制到地址空间中
    • 赋予可读、可写、可执行权限
  • 然后跳转到 _start 执行

ELF 并没有多做多少

  • 多段字节序列复制到地址空间中
    • 分别赋予可读/可写/可执行权限
  • 然后跳转到指定的 entry (默认为 _start) 执行
2024 南京大学《操作系统:设计与实现》
ELF 静态链接和加载

加载:ELF v.s. FLE (cont'd)

它们都是数据结构

  • 区别:ELF 是 “二进制数据结构”
  • readelf -l 描述了如何加载它
    • Offset: segment 在文件中的偏移量
    • VirtAddr: 段在内存中应当被加载到的起始地址
    • PhysAddr (一般不用)
    • FileSiz: 段在文件中的字节数
    • MemSiz: 段在内存中的字节数 (可能大于文件大小)
    • Flags: 权限,例如 RWE
    • Align: 虚拟地址的对齐
2024 南京大学《操作系统:设计与实现》
ELF 静态链接和加载

实现 ELF 的静态加载

实现 my_execve(): 问题分析

  • 得到 ELF 文件中的数据结构描述
  • 按照 “要求” 执行 mmap 系统调用
  • 创建 Initial Process Stack
  • 构成进程初始状态
    • 理论上我们可以实现 “没有 execve 的 execve”
    • my_execve() 在其他地方也有:AbstractMachine

思考题 🌶🌶️

  • my_execve 如何释放旧进程的内存资源?
2024 南京大学《操作系统:设计与实现》