.text 段
说明:
- 存放机器指令(即程序的代码部分)。
- 所有函数(如
_start或main)的指令代码都在该段中。 - 此段默认是只读和可执行的,不允许写操作。
访问权限:
| 可读 | 可写 | 可执行 |
|---|---|---|
| 是 | 否 | 是 |
运行时位置:
- 被加载到程序的代码段(Code Segment)。
- 在 Linux 下,通常映射到虚拟地址空间如
0x400000。
示例代码:
.section .text
.globl _start
_start:
mov $60, %rax # exit 系统调用号
xor %rdi, %rdi # 退出码 0
syscall # 发起系统调用
备注:
.text段不能在运行时修改,否则会触发段错误(Segmentation Fault)。- 操作系统通过内存页保护机制保证此段不可写,防止代码注入等攻击。
.data 段
说明:
- 存放已初始化的全局或静态变量。
- C 中如
int x = 42;的变量通常存放在.data段中。
访问权限:
| 可读 | 可写 | 可执行 |
|---|---|---|
| 是 | 是 | 否 |
运行时位置:
- 被加载到数据段(Data Segment),一般在
.text段之后。 - 典型地址在虚拟内存中是
0x600000左右。
示例代码:
.section .data
value: .long 1234
可以在运行时修改该值,例如:
mov $5678, value(%rip)
备注:
.data段在 ELF 文件中占有空间,初始值也包含在可执行文件中。- 运行时可以随时读写
.data中的数据。
.bss 段
说明:
- 存放未初始化的全局或静态变量。
- 如 C 中的
char buf[64];(未赋初值)变量会被分配在.bss段。 - 在程序运行时由操作系统分配并清零。
访问权限:
| 可读 | 可写 | 可执行 |
|---|---|---|
| 是 | 是 | 否 |
运行时位置:
- 程序加载时分配在 BSS 区域,通常在
.data段之后。 - 初始值为 0,不占用 ELF 文件实际空间,仅记录大小。
示例代码:
.section .bss
.lcomm buf, 64
等价于:
char buf[64]; // 自动初始化为全 0
备注:
.bss是为了节省文件大小,不将初始化数据写入 ELF 文件。- 使用
.lcomm定义未初始化空间时只影响链接后的内存分布。
.rodata 段
说明:
- 存放只读数据,如字符串常量、数学常量等。
- 对应于 C 中的
const char *s = "hello";这类常量。
访问权限:
| 可读 | 可写 | 可执行 |
|---|---|---|
| 是 | 否 | 否 |
运行时位置:
- 一般与
.text段临近,也可能独立映射为只读段。 - 操作系统使用内存页权限将其标记为只读,不可写。
示例代码:
.section .rodata
msg: .asciz "hello world\n"
使用时,在 .text 段内:
mov $msg, %rdi
call puts
备注:
.rodata是安全和性能优化的重要部分。- 程序试图修改
.rodata会导致段错误。 - 多进程程序可共享该段内存(因其不变性)。
总结对比表
.section | 说明 | 可读 | 可写 | 可执行 | 初始值 | 是否在 ELF 文件中占空间 | 运行时是否可修改 |
|---|---|---|---|---|---|---|---|
.text | 存放程序指令 | 是 | 否 | 是 | 有 | 是 | 否 |
.data | 已初始化的全局/静态变量 | 是 | 是 | 否 | 有 | 是 | 是 |
.bss | 未初始化变量 | 是 | 是 | 否 | 全 0 | 否(仅记录大小) | 是 |
.rodata | 字符串常量、只读数据 | 是 | 否 | 否 | 有 | 是 | 否 |