可执行文件的ELF文件有一个程序(段)标题和一个节标题,可以通过readelf -a
看到,这是一个例子:
上面的两张图片分别是节标题和节目(段)标题。可以看出,段头由几个段头组成,用于将程序加载到内存中。
是否只需将.text,.rodata,.data,.bss部分加载到内存中?
段中的所有其他部分(例如,第3段中的.ctors,.dtors .jcr)是否用于对齐?
答案 0 :(得分:21)
部分和细分是两个完全不同的概念。部分涉及存储在那里的数据的语义(即它将用于什么),并且除了调试目的之外,一旦链接了程序或共享库,它们实际上是无关紧要的。你甚至可以完全删除部分标题(或用随机垃圾覆盖它们),程序仍然有效。
段(即程序头加载指令)是内核和/或动态链接器在加载程序时实际查看的内容。例如,在您的情况下,您有两个加载指令。第一个导致文件的第一个4k(1页)映射到地址0x08048000,并指示实际上只使用该映射的第一个0x4b8字节(其余的是对齐)。第二个导致文件的前8k(2页)映射到地址0x08049000。其中绝大多数是一致的。第一个0xf14字节不是load指令的一部分(只是对齐)并且将被浪费。从0x08049f14开始,实际使用从文件映射的0x108字节,并且加载器(内核或动态链接器)将另外的0x10字节(达到0x118的MemSize)填充为零。这跨越到0x0804a02c(在第二个映射页面中)。第二个映射页面的其余部分未使用/浪费(但malloc
可能能够将其恢复以用作堆的一部分。)
最后,虽然根本不会使用节标题,但程序在运行时可能会使用许多不同节的内容。请注意,.ctors
和.dtors
的地址范围位于第二个加载映射的开头,因此它们在运行时被映射并可由程序访问(运行时启动/退出代码将使用它们运行全局构造函数和析构函数,如果使用C ++或带有ctor / dtor属性的“GNU C”代码)。另请注意,.data
从地址0x0804a00c开始,在第二个映射页面中。这允许在应用重定位后将第一页保护为只读(程序头中的RELRO指令)。