gcc / ld:静态链接 ELF 二进制文件中的重叠部分(.tbss、.init_array)

2023-12-31

我正在 x86_64 机器上的 Debian 7 系统上使用 gcc 版本 4.8.2 (Debian 4.8.2-21) 静态编译一个非常简单的 hello-world 单行代码:

gcc test.c -static -o test

我得到一个可执行的 ELF 文件,其中包含以下部分:

[17] .tdata            PROGBITS         00000000006b4000  000b4000
     0000000000000020  0000000000000000 WAT       0     0     8
[18] .tbss             NOBITS           00000000006b4020  000b4020
     0000000000000030  0000000000000000 WAT       0     0     8
[19] .init_array       INIT_ARRAY       00000000006b4020  000b4020
     0000000000000010  0000000000000000  WA       0     0     8
[20] .fini_array       FINI_ARRAY       00000000006b4030  000b4030
     0000000000000010  0000000000000000  WA       0     0     8
[21] .jcr              PROGBITS         00000000006b4040  000b4040
     0000000000000008  0000000000000000  WA       0     0     8
[22] .data.rel.ro      PROGBITS         00000000006b4060  000b4060
     00000000000000e4  0000000000000000  WA       0     0     32

注意.tbss该节分配在地址 0x6b4020..0x6b4050(0x30 字节)处,并且与.init_array0x6b4020..0x6b4030 处的部分(0x10 字节),.fini_array0x6b4030..0x6b4040(0x10 字节)处的部分以及.jcr0x6b4040..0x6b4048 处的部分(8 字节)。

注意它确实如此not与以下部分相交,例如,.data.rel.ro,但这可能是因为.data.rel.ro对齐方式为 32,因此不能放置在 0x6b4060 之前。

生成的文件运行正常,但我仍然不明白它是如何工作的。根据我在 glibc 文档中读到的内容,.tbss是一个公正的.bss线程本地存储部分(即分配的内存暂存空间,未真正映射到物理文件中)。是那个吗.tbss部分非常特殊以至于可以与其他部分重叠?是.init_array, .fini_array and .jcr如此无用(例如,与 TLS 相关的代码运行后不再需要它们),因此它们可以被 bss 覆盖吗?或者这是某种错误?

基本上,如果我尝试在应用程序中读取地址 0x6b4020,我可以读取和写入什么?.tbss内容或.init_array指点?为什么?


的虚拟地址.tbss没有意义,因为该部分仅用作 GLIBC 中线程实现分配的 TLS 存储的模板。

这个虚拟地址的实现方式是.tbss如下.tbdata在默认链接描述文件中:

...
.gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
/* Thread Local Storage sections  */
.tdata          : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss           : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array     :
{
  PROVIDE_HIDDEN (__preinit_array_start = .);
  KEEP (*(.preinit_array))
  PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array     :
{
   PROVIDE_HIDDEN (__init_array_start = .);
   KEEP (*(SORT(.init_array.*)))
   KEEP (*(.init_array))
   PROVIDE_HIDDEN (__init_array_end = .);
}
...

因此它的虚拟地址就是前一节的虚拟地址(.tbdata)加上前一部分的大小(最终使用一些填充以达到所需的对齐方式)。.init_array (or .preinit_array如果存在)接下来是它的位置应该以相同的方式确定,但是.tbss众所周知,它非常特别,因此在 GNU LD 中对其进行了深度硬编码处理:

/* .tbss sections effectively have zero size.  */
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
    || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
    || link_info.relocatable)
  dotdelta = TO_ADDR (os->bfd_section->size);
else
  dotdelta = 0;    // <----------------
dot += dotdelta;

.tbss不可重定位,它具有SEC_THREAD_LOCAL标志已设置,并且它没有内容(NOBITS),因此else分支被采取。换句话说,无论规模有多大.tbss也就是说,链接器不会提前移动其后面的部分的位置(也称为“点”)。

另请注意.tbss位于不可加载的 ELF 段中:

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x00000000000b1f24 0x00000000000b1f24  R E    200000
  LOAD           0x00000000000b2000 0x00000000006b2000 0x00000000006b2000
                 0x0000000000002288 0x00000000000174d8  RW     200000
  NOTE           0x0000000000000158 0x0000000000400158 0x0000000000400158
                 0x0000000000000044 0x0000000000000044  R      4
  TLS            0x00000000000b2000 0x00000000006b2000 0x00000000006b2000 <---+
                 0x0000000000000020 0x0000000000000060  R      8              |
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000     |
                 0x0000000000000000 0x0000000000000000  RW     8              |
                                                                              |
 Section to Segment mapping:                                                  |
  Segment Sections...                                                         |
   00     .note.ABI-tag ...                                                   |
   01     .tdata .ctors ...                                                   |
   02     .note.ABI-tag ...                                                   |
   03     .tdata .tbss    <---------------------------------------------------+
   04
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

gcc / ld:静态链接 ELF 二进制文件中的重叠部分(.tbss、.init_array) 的相关文章

随机推荐