LOAD程序头中的偏移为何与地址空间中的偏移不匹配?
为何ELF LOAD段偏移与pmap输出不一致?
问题详情
我有如下ELF程序头信息:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x002dd0 0x0000000000003dd0 0x0000000000003dd0 0x000250 0x000258 RW 0x1000
该LOAD段本应映射以下节:
.init_array .fini_array .dynamic .got .got.plt .data .bss
执行readelf -l program可以确认这些节的起始地址确实是0x002dd0:
Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al (...) [20] .init_array INIT_ARRAY 0000000000003dd0 002dd0 000008 08 WA 0 0 8 [21] .fini_array FINI_ARRAY 0000000000003dd8 002dd8 000008 08 WA 0 0 8 [22] .dynamic DYNAMIC 0000000000003de0 002de0 0001e0 10 WA 7 0 8 [23] .got PROGBITS 0000000000003fc0 002fc0 000028 08 WA 0 0 8 [24] .got.plt PROGBITS 0000000000003fe8 002fe8 000028 08 WA 0 0 8 [25] .data PROGBITS 0000000000004010 003010 000010 00 WA 0 0 8 [26] .bss NOBITS 0000000000004020 003020 000008 00 WA 0 0 1
但启动进程后通过pmap查看,对应映射的偏移是0x003000而非0x002dd0:
Address Perm Offset Inode Size Rss Anonymous Mapping 63a2b2ccb000 rw-p 00003000 5243856 4 4 4 program
疑惑点:如果偏移从0x003000开始,那0x002dd0-0x002fff范围内的数据岂不是丢失了?
原因分析
这是**RELRO(重定位只读)**机制导致的,具体逻辑如下:
- RELRO是一种程序安全机制,会把
.init_array、.fini_array、.dynamic、.got这些原本属于RW(读写)LOAD段的节设置为只读权限,系统会为这部分内容单独创建一个新的只读映射(权限通常为r--p),0x002dd0-0x002fff范围的内容就属于这个只读映射,你可以在pmap的完整输出里找到对应的条目。 - 你看到的
0x003000偏移的RW映射,只包含.data和.bss这两个仍需要读写权限的节,所以不存在数据丢失的情况——只是原本的一个LOAD段被RELRO拆分成了两个不同权限的映射段,以此提升程序安全性,防范内存篡改类攻击。
内容的提问来源于stack exchange,提问作者Wiertek
相关产品推荐
相关产品推荐

