我是编译器的初学者,但我对了解程序的结构(二进制)以及如何读取和加载到内存中执行非常感兴趣。你们建议我阅读哪些电子书/书籍/教程以便快速入门?
2 回答
ELF 文件布局
一个 ELF 文件有两个视图:
- 程序头显示运行时使用的段
- 节头列出了二进制文件的节集
每个 ELF 文件由一个 ELF 头组成,后面是文件数据。
文件数据可以包括:
- 程序头表,描述零个或多个段
- 节头表,描述零个或多个节
- 程序头表或节头表中的条目所引用的数据
段包含文件运行时执行所需的信息,而节包含用于链接和重定位的重要数据。整个文件中的任何字节最多只能由一个节拥有,并且可以有不属于任何节的孤儿字节。
将程序加载到内存
在计算中,加载程序是操作系统中负责加载程序的部分。
它是启动程序过程中的重要阶段之一,因为它将程序放入内存并为执行做好准备。
加载程序涉及:
- 将包含程序文本的可执行文件的内容读入内存
- 执行其他所需的准备任务以准备可执行文件以运行。
加载完成后,操作系统通过将控制权传递给加载的程序代码来启动程序。
*NIX 方式
在 Unix 中,加载程序是系统调用的处理程序
execve()
。Unix 加载器的任务包括:
- 验证(权限、内存要求等)
- 将程序映像从磁盘复制到主存储器
- 在堆栈上复制命令行参数
- 初始化寄存器(例如,堆栈指针)
- 跳转到程序入口点 (
_start
)
编译器和可执行二进制文件是远程相关的。(实际的可执行文件是由链接器构建的ld
,而不是编译器)。
在 Linux 系统上,Linux 内核使用写时复制和按需分页技术来延迟加载程序页面,用于ELF可执行文件。共享库可以动态加载,最好包含与位置无关的代码。
您可能有兴趣阅读有关编译器构造、Levine 关于链接器和加载器的书、Linux 汇编方法、程序库方法、ldd(1)、execve(2)、intro(2)、fork(2)、mmap( 2)、dlopen(3)、elf(5)、proc(5)、signal(7)手册页。
还要尝试了解cat /proc/self/maps
向您展示的内容(执行该操作的进程的内存映射cat
)。你也可以玩objdump
。