author: hjjdebug
date: 2026年 01月 27日 星期二 14:09:52 CST
descrip: elf 文件, 结构概念思考
文章目录
- 1. elf 文件中的段和节有什么区别和联系?
- 2. 段的结构定义
- 3. 节的结构定义
- 4. 局部变量会形成符号吗?
- 5. 结构类型定义会形成符号吗?
- 6. 宏定义会形成符号吗?
- 7. 符号的值一定是内存地址吗? 其值会不会有其它类型?
- 8. 符号和重定位符号有什么区别.
1. elf 文件中的段和节有什么区别和联系?
段和节都是用来描述一块数据, 这就是它们相同的地方.
都是描述一块数据, 为什么还要区分断和节呢?
节: 描述的是链接器需要的数据块信息.
段: 描述的是加载期需要的数据块信息.
编译生成节信息,供链接器使用. 定义文件中的位置信息和属性
链接生成段信息,供加载器使用. 定义内存中的位置信息和属性
一个段可以有多个节构成, 这时各个节的属性要一致.因为节的属性
构成段的属性(可读,可写,可运行等)
典型的节: .text,.data,.rodata,.bss 等
典型的段: PT_LOAD 段, program table load 段.
elf 文件可以有多个PT_LOAD 段, 例如把.text, .rodata映射到只读存储区.
把.data,.bss 映射到可读写区.
2. 段的结构定义
typedef struct {
Elf32_Word p_type; /* 段类型,如 PT_LOAD、PT_DYNAMIC 等/
Elf32_Off p_offset; /段在文件中的偏移量/
Elf32_Addr p_vaddr; /段在内存中的虚拟地址/
Elf32_Addr p_paddr; /段在内存中的物理地址(通常与 vaddr 相同)/
Elf32_Word p_filesz; /段在文件中的大小/
Elf32_Word p_memsz; /段在内存中的大小/
Elf32_Word p_flags; /段的标志,如可读、可写、可执行/
Elf32_Word p_align; /段在内存中的对齐方式 */
} Elf32_Phdr;
可见段不仅描述了在文件中的偏移地址,文件大小,
还描述了在内存中的物理地址,虚拟地址(通常一致)和内存大小.
其它信息为类型,标记和对齐方式.
3. 节的结构定义
typedef struct {
Elf32_Word sh_name; /* 节的名称在字符串表中的索引/
Elf32_Word sh_type; /节的类型,如 SHT_PROGBITS、SHT_SYMTAB 等/
Elf32_Word sh_flags; /节的标志,如 SHF_WRITE、SHF_ALLOC 等/
Elf32_Addr sh_addr; /节在内存中的地址(仅在链接后有效)/
Elf32_Off sh_offset; /节在文件中的偏移量/
Elf32_Word sh_size; /节的大小/
Elf32_Word sh_link; /与节相关的链接信息/
Elf32_Word sh_info; /额外的节信息/
Elf32_Word sh_addralign; /节的对齐方式/
Elf32_Word sh_entsize; /节中每个条目的大小 */
} Elf32_Shdr;
首先一致的地方是节在文件中的偏移量,节的大小, 也保留了在内存中的地址(链接后有效).
其它信息也由类型,标志,对齐方式.
比段多出的信息包括节的名称, 节是有名称的,而段不需要.
节中有每个条目的大小, 这主要针对符号表, 重定位表结构,它们包含多个重复结构.
像.text, .data 节等是没有entity 大小的.
4. 局部变量会形成符号吗?
局部变量虽然有相对于栈帧的固定偏移地址, 但栈帧位置是动态的,不确定的.
符号主要是针对固定地址而设计的,所以局部变量不会形成符号.
5. 结构类型定义会形成符号吗?
结构类型定义虽然也有名称, 但它不会形成符号, 因为类型并没有对应内存中的一个地址,
也没有对应一个数值.
结构体定义一个全局变量或静态变量, 变量会对应内存中一个位置,变量会形成符号.
6. 宏定义会形成符号吗?
宏定义虽然也有名称, 但它不会对应符号,宏定义值是预处理阶段的文本替换.
而不是链接阶段生成的内存地址.
7. 符号的值一定是内存地址吗? 其值会不会有其它类型?
符号表示内存地址,这时最常见的情景,如全局变量,静态变量,函数地址.
也有其它类型, 例如常量.
汇编中的.equ 存储的是常量, 例如
.equ SYSSEG, 0x1000
.equ SYSSIZE, 0x3000
用nm 查看它的类型是a, a表示 absolute 的意思, 绝对的,不变的.
注意:汇编中的NEXT, , LABEL1 等, 存储的是地址.
c 语言的goto label, 存储的也是地址.
类型上还可以再细划分,但我见到的就是地址和常量了, 而且常量非常少,c语言好像就没有.
因为c语言的宏不会形成符号.
本来,汇编的equ 是不必形成符号的, 符号的用途是为了连接.
不为连接的符号没有什么意义. 或者仅具有显示的意义.
所以可以这样讲, 符号一般都对应内存地址. 那些不对应内存地址的符号就没多少意义了.
8. 符号和重定位符号有什么区别.
符号,可以认为是内存地址
重定位符号,就是还没有确定具体地址的内存地址, 地址的确定要等加载完成实际上是执行时才能确定.
加载的时候只是加载了桩地址, 运行时才确定地址,这叫延时绑定机制.这里就不详细说了.
可参考我的其它博客.