土法炼钢兴趣小组的算法知识备份

【操作系统百科】ELF 加载

文章导航

分类入口
os
标签入口
#elf#execve#dynamic-linker#got-plt#pie

目录

execve("/usr/bin/ls", ...) → 内核加载 ELF 文件 → 设置用户空间 → 跳转到入口点。整个过程涉及内核 binfmt_elf、mmap、动态链接器。

一、先看图

flowchart TD
    EXECVE[execve] --> BINFMT[binfmt_elf<br/>识别 ELF magic]
    BINFMT --> PTLOAD[mmap PT_LOAD 段<br/>.text / .data / .bss]
    PTLOAD --> INTERP{有 PT_INTERP?}
    INTERP -- 是 --> LDSO[加载 ld.so<br/>动态链接器]
    INTERP -- 否 --> ENTRY[跳转到 e_entry<br/>静态链接]
    LDSO --> RESOLVE[解析共享库<br/>GOT/PLT 初始化]
    RESOLVE --> MAIN[_start → __libc_start_main → main]

    classDef kern fill:#388bfd22,stroke:#388bfd,color:#adbac7;
    classDef user fill:#3fb95022,stroke:#3fb950,color:#adbac7;
    class EXECVE,BINFMT,PTLOAD,INTERP kern
    class LDSO,RESOLVE,MAIN,ENTRY user

二、ELF 结构

ELF Header → Program Headers → Sections

关键 Program Header 类型:

类型 用途
PT_LOAD 可加载段(.text, .data)
PT_INTERP 动态链接器路径
PT_DYNAMIC 动态链接信息
PT_GNU_STACK 栈属性(NX)
PT_GNU_RELRO 只读重定位

三、内核加载

// fs/binfmt_elf.c
static int load_elf_binary(struct linux_binprm *bprm)
{
    // 1. 读 ELF header
    // 2. 遍历 PT_LOAD → mmap 每个段
    // 3. 设置 brk(堆起点)
    // 4. 加载 PT_INTERP 指定的 ld.so
    // 5. 设置 aux vector
    // 6. 跳转到入口点
}

四、动态链接器(ld.so)

readelf -l /usr/bin/ls | grep INTERP
# [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

内核加载 ld.so → 跳转到 ld.so 入口 → ld.so 完成:

  1. 解析 .dynamic
  2. 加载所有 DT_NEEDED 共享库
  3. 重定位(填 GOT 表)
  4. 跳转到程序 _start

五、GOT/PLT 延迟绑定

调用 printf → PLT stub → 第一次跳转到 ld.so resolver → 填 GOT → 后续直接跳

PLT(Procedure Linkage Table)+ GOT(Global Offset Table)实现延迟绑定:

LD_BIND_NOW=1:启动时立即绑定所有符号(加载慢,运行快)。

六、PIE(Position-Independent Executable)

现代发行版默认编译为 PIE:

file /usr/bin/ls
# ELF 64-bit LSB pie executable

PIE + ASLR → 每次加载地址随机 → 增加攻击难度。

七、Auxiliary Vector

内核通过栈传递信息给用户态:

// include/uapi/linux/auxvec.h
AT_ENTRY     // 程序入口点
AT_PHDR      // Program header 地址
AT_BASE      // ld.so 基址
AT_RANDOM    // 16 字节随机数
AT_SYSINFO_EHDR  // vDSO 地址
LD_SHOW_AUXV=1 /usr/bin/true

八、安全相关

特性 保护
ASLR + PIE 地址随机化
NX Stack 栈不可执行
RELRO GOT 只读(Full RELRO)
Stack Canary 栈溢出检测
FORTIFY_SOURCE 缓冲区溢出检测

九、观察

readelf -h /usr/bin/ls     # ELF header
readelf -l /usr/bin/ls     # Program headers
readelf -d /usr/bin/ls     # Dynamic section
ldd /usr/bin/ls            # 共享库依赖

# 加载过程
LD_DEBUG=all /usr/bin/ls 2>&1 | head -50
strace -e mmap,mprotect execve /usr/bin/ls

十、小结


参考文献

工具


上一篇initramfs 下一篇vDSO

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-04-27 · os

【操作系统百科】内存回收

Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。

2026-04-28 · os

【操作系统百科】交换

swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。

2026-05-03 · os

【操作系统百科】Slab/SLUB 分配器

buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。

2026-05-07 · os

【操作系统百科】用户态分配器

glibc malloc、tcmalloc、jemalloc、mimalloc 各有哲学。本文讲 arena、thread cache、size class、madvise 返还策略、碎片与 RSS 膨胀、如何根据负载选分配器。


By .