为何部分ELF节会被映射到多个程序段?(Android NDK场景)
ELF节被映射到多个程序段的原因解析
在对一个简单的Android NDK二进制文件执行readelf命令时,发现部分ELF节(比如.note.gnu.build-id、.note.android.ident、.eh_frame_hdr、.dynamic、.got等)被映射到多个程序段,请问该现象的原因是什么?
对应的readelf输出信息如下:
readelf libhellondk.so -lW Elf file type is DYN (Shared object file) Entry point 0xef30 There are 8 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0301d8 0x0301d8 R E 0x1000 LOAD 0x030d48 0x0000000000031d48 0x0000000000031d48 0x0032e0 0x003768 RW 0x1000 DYNAMIC 0x033aa0 0x0000000000034aa0 0x0000000000034aa0 0x0001f0 0x0001f0 RW 0x8 NOTE 0x000200 0x0000000000000200 0x0000000000000200 0x000024 0x000024 R 0x4 NOTE 0x030140 0x0000000000030140 0x0000000000030140 0x000098 0x000098 R 0x4 GNU_EH_FRAME 0x02b144 0x000000000002b144 0x000000000002b144 0x000e34 0x000e34 R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x030d48 0x0000000000031d48 0x0000000000031d48 0x0032b8 0x0032b8 R 0x1 Section to Segment mapping: Segment Sections... 00 .note.gnu.build-id .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .plt .text .rodata .eh_frame_hdr .eh_frame .gcc_except_table .note.android.ident 01 .fini_array .data.rel.ro .dynamic .got .data .bss 02 .dynamic 03 .note.gnu.build-id 04 .note.android.ident 05 .eh_frame_hdr 06 07 .fini_array .data.rel.ro .dynamic .got
原因解析
- LOAD段是内存加载的基础:LOAD类型的程序段负责把ELF文件中的内容实际加载到内存中,所有需要驻留内存的节都会被包含在至少一个LOAD段里。比如
.note.gnu.build-id属于只读可执行的LOAD0段,.dynamic属于读写的LOAD1段,这是程序运行的基本要求。 - 专用程序段是元信息标记:那些重复映射的段(NOTE、DYNAMIC、GNU_EH_FRAME、GNU_RELRO)并不是重复加载内容,而是给系统加载器/动态链接器提供快速定位关键信息的标记:
- NOTE段:直接标记
.note.gnu.build-id、.note.android.ident这类元数据节,让加载器不用遍历整个LOAD段就能获取构建ID、平台标识等信息。 - DYNAMIC段:专门指向
.dynamic节,动态链接器需要靠这个节处理依赖库加载、符号重定位等核心逻辑,单独标记能提升访问效率。 - GNU_EH_FRAME段:标记
.eh_frame_hdr节,这是C++异常处理的关键元数据,调试器或异常处理机制可以快速定位它。 - GNU_RELRO段:标记
.dynamic、.got等需要设置只读保护的区域,这是一种安全机制,加载器初始化完成后会把这段内存设为只读,防止恶意篡改。
- NOTE段:直接标记
- 无内存冗余:这些"重复映射"只是逻辑上的段标记,物理内存中对应的节内容只会被加载一次,多个程序段只是指向同一块内存地址,不会浪费内存空间。
内容的提问来源于stack exchange,提问作者Fee
相关产品推荐
相关产品推荐

