一 概述
二 类型
三 语句
四 函数
五 数据
六 内存
七 代码
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
6. 进程装载
程序(或可执行文件)是静态概念,是一个包含 “已编译” 指令和数据的集合,而进程是运行期动态概念。
建立进程:
- 创建独立虚拟地址空间。
- 读取文件头,建立虚拟空间映射关系(section to segment)。
- 将 IP/PC 设置成可执行文件入口(entry point),开始执行。
进程是资源单位,线程是执行单位。每个进程都有一个标识编号 PID。内核使用 PCB(process control block)保存进程状态(status, IP/PC, register, openfiles)。所有 PCB 保存在进程表(process table)内。
创建虚拟空间实际是创建映射所需的各种数据结构。
建立映射关系,则是读取 program header ,它包含了段合并和装载设置(地址和权限)。
$ readelf -l ./test Section to Segment mapping: Segment Sections... 00 01 .interp
$ ldd ./test linux-vdso.so.1 (0x00007ffcf79ec000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa010663000) # 运行库 /lib64/ld-linux-x86-64.so.2 (0x00007fa01085b000) # 动态链接器
如果 section 是链接视图(view),那么 segment 则是执行视图。特殊 vvar, vsdo、vsyscall 段,由内核映射到用户空间,加速部分系统调用(libc),减少上下文切换。其中 vsdo(linux-vdso.so)是 vsyscall 改进,不再使用固定地址,ASLR 随机化。至于 vvar,用于获取内核返回数据(只读)。
实际执行过程:
- 调用
fork()
创建新进程。 - 调用
exec()
加载文件。
- 检查 magic、section 等。
- 通过 .interp 设置动态链接器路径。(ld-linux-x86-64.so)
- 根据 segment 进行内存分段映射。(.text, .data, .bss ...)
- 初始化执行环境。
- 设置执行入口点。(entry point, _start, PC/IP)
链接器 ld 默认以
_start
标签为入口,可以通过参数自定义。实际执行顺序为_start > __libc_start_main > _init > main > exit > _exit
。
x64 进程内存模型示例
| | 0x400000 +--------------+ | .init, .text | +--------------+ | .rodata | +--------------+ | .data, .bss | +--------------+ | heap | v +--------------+ | ... | mmap +--------------+ | dynlib | +--------------+ | ... | +--------------+ | stack | ^ 0x7ffffffff000 +--------------+ | vsyscall |
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论