ELF文件中的“节到段映射”存储在哪里?

21

作为尝试从零开始编写编译器的一部分,我目前正在处理处理ELF文件的部分。

经过阅读多篇文章和规范,我仍然不太明白节到段映射存储在哪里。 当观察使用NASM+ld生成的小型可执行文件时,我可以看到.text节被某种方式映射到LOAD类型的程序头上,但是如何实现呢?

给定一个小型(工作)可执行文件作为输入时,readelf输出的一小部分内容:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000084 0x0000000000000084  R E    200000

 Section to Segment mapping:
  Segment Sections...
   00     .text 

这个映射是否需要才能生成可执行文件?或者它们可以完全省略,你仍然会有一个有效的可执行文件吗?

2个回答

31

我仍然不太明白节到段的映射存储在哪里。

它们并不会被任何地方存储。

相反,readelf通过查看节和段的文件偏移量和大小来计算映射关系。


1
文件偏移量,就是这样!我以为它与相等的虚拟内存地址有关。谢谢,它有效了。 - BizarreCake
你的意思是:如果可执行文件包含可选的节头表,那么该表将指向包含这些节的段的中间位置,是这样吗? - Ciro Santilli OurBigBook.com
嗯,那我不明白它如何能够按需计算(除了我之前的评论所说的“按需”,但需要可选的部分标题)。我的意思是,如果没有选项部分标题,那么它就无法确定对吧? - Ciro Santilli OurBigBook.com
3
如果没有节标题,那么readelf将不会生成“段到节的映射”输出。 - Employed Russian
1
你如何确定是否有节头?是使用readelf -S命令吗?如果它给出了输出,那么你就有一个节头表了吗?在注释中,它被称为“可选”节头,这意味着只有其中一个存在。你是指节头数组吗? - Har
1
@Har,您可以使用readelf --sections --wide a.out命令找到一个名为“Sections”的部分。需要注意的是,节头是可选的,并且可能根本不存在。 - clockw0rk

4

我根据@Employed Russian的建议进行了一项测试。

运行命令:readelf -l ./libandroid_servers.so

Elf file type is DYN (Shared object file)
Entry point 0x0
There are 6 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x000c0 0x000c0 R   0x4
  LOAD           0x000000 0x00000000 0x00000000 0x0f830 0x0f830 R E 0x1000
  LOAD           0x010000 0x00010000 0x00010000 0x00cf4 0x011ac RW  0x1000
  DYNAMIC        0x010540 0x00010540 0x00010540 0x00130 0x00130 RW  0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0
  EXIDX          0x00f2e8 0x0000f2e8 0x0000f2e8 0x00548 0x00548 R   0x4

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .hash .dynsym .dynstr .rel.plt .rel.dyn .plt .text .rodata .ARM.extab .ARM.exidx 
   02     .init_array .fini_array .data.rel.ro .dynamic .got .data .bss 
   03     .dynamic 
   04     
   05     .ARM.exidx 

01 加载偏移量:0x000000 文件大小:0x0f830
.ARM.exidx 段结束地址:hex(0x00f2e8 + 0x00548) = 0xf830

02 加载偏移量:0x010000 文件大小:0x00cf4
.init_array 段起始地址:10000h
.bss 段结束地址:hex(0x00f2e8 + 0) = 0x10cf4

你可以看到,readelf 明确按照计算结果将段打印出来。它们匹配得很好。


1
节只在链接时可用。段在执行时可用。段基本上只是大块的数据,即多个节被淬合到相应的段中。您可以使用节到段映射查看哪些节位于哪个段中。 - clockw0rk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接