本文介绍了gcc / ld:静态链接的ELF二进制文件中的重叠部分(.tbss,.init_array)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我在x86_64机器上使用gcc 4.8.2版(Debian 4.8.2-21)在Debian 7系统上静态编译一个非常简单的hello-world单行程: .tbss 的虚拟地址没有意义,因为部分仅用作由GLIBC中的线程实现分配的TLS存储的模板。 这个虚拟地址到位的方式是 .tbss 在默认链接描述文件中遵循 .tbdata : $ b .gcc_except_table:ONLY_IF_RW {*(.gcc_except_table .gcc_except_table。*)} / *线程本地存储部分* / .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 (或 .preinit_array 如果存在的话)接下来,它的位置应该以相同的方式确定,但 .tbss 非常特别,它在GNU LD内部被赋予了一个深刻的硬编码处理: / * .tbss部分实际上具有零大小。 ((os-> bfd_section->标志& SEC_HAS_CONTENTS)!= 0 ||(os-> bfd_section->标志& 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分段中: 程序标题:类型偏移量VirtAddr PhysAddr FileSiz MemSiz标志对齐 LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000 0x00000000000b1f24 0x00000000000b1f24 RE 200000 LOAD 0x00000000000b2000 0x00000000006b2000 0x00000000006b2000 0x0000000000002288 0x00000000000174d8 RW 200000 注意0x0000000000000158 0x0000000000400158 0x0000000000400158 0x0000000000000044 0x0000000000000044 R 4 TLS 0x00000000000b2000 0x00000000006b2000 0x00000000006b2000 0x0000000000000020 0x0000000000000060 R 8 | GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 | 0x0000000000000000 0x0000000000000000 RW 8 | | 部分到段映射:| 细分市场... | 00 .note.ABI-tag ... | 01 .tdata .ctors ... | 02 .note.ABI-tag ... | 03 .tdata .tbss< --------------------------------------- ------------ + 04 I'm compiling a very simple hello-world one-liner statically on Debian 7 system on x86_64 machine with gcc version 4.8.2 (Debian 4.8.2-21):gcc test.c -static -o testand I get an executable ELF file that includes the following sections:[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 32Note that .tbss section is allocated at addresses 0x6b4020..0x6b4050 (0x30 bytes) and it intersects with allocation of .init_array section at 0x6b4020..0x6b4030 (0x10 bytes), .fini_array section at 0x6b4030..0x6b4040 (0x10 bytes) and with .jcr section at 0x6b4040..0x6b4048 (8 bytes).Note it does not intersect with the following sections, for example, .data.rel.ro, but that's probably because .data.rel.ro alignment is 32 and thus it can't be placed any earlier than 0x6b4060.The resulting file runs ok, but I still don't exactly get how it works. From what I read in glibc documentation, .tbss is a just .bss section for thread local storage (i.e. allocated memory scratch space, not really mapped in physical file). Is it that .tbss section is so special that it can overlap other sections? Are .init_array, .fini_array and .jcr are so useless (for example, they are not needed anymore then TLS-related code runs), so they can be overwritten by bss? Or is it some sort of a bug?Basically, what do I get to read and write if I'll try to read address 0x6b4020 in my application? .tbss contents or .init_array pointers? Why? 解决方案 The virtual address of .tbss is meaningless as that section only serves as a template for the TLS storage as allocated by the threading implementation in GLIBC.The way this virtual address comes into place is that .tbss follows .tbdata in the default linker script:....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 = .);}...therefore its virtual address is simply the virtual address of the preceding section (.tbdata) plus the size of the preceding section (eventually with some padding in order to reach the desired alignment). .init_array (or .preinit_array if present) comes next and its location should be determined the same way, but .tbss is known to be so very special, that it is given a deeply hard-coded treatment inside 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 is not relocatable, it has the SEC_THREAD_LOCAL flag set, and it does not have contents (NOBITS), therefore the else branch is taken. In other words, no matter how large the .tbss is, the linker does not advance the location of the section that follows it (also know as "the dot").Note also that .tbss sits in a non-loadable ELF segment: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 这篇关于gcc / ld:静态链接的ELF二进制文件中的重叠部分(.tbss,.init_array)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 09-11 02:04