【发布时间】:2014-10-19 11:55:32
【问题描述】:
我正在使用 gcc 版本 4.8.2(Debian 4.8.2-21)的 x86_64 机器上的 Debian 7 系统上静态编译一个非常简单的 hello-world one-liner:
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_array 部分在 0x6b4020..0x6b4030(0x10 字节)的分配相交,.fini_array 部分在 0x6b4030..0x6b4040 (0x10 字节),.jcr 部分位于 0x6b4040..0x6b4048(8 字节)。
注意它不与以下部分相交,例如.data.rel.ro,但这可能是因为.data.rel.ro 对齐是32,因此它不能放置在0x6b4060 之前。
生成的文件运行正常,但我仍然不完全了解它是如何工作的。从我在 glibc 文档中读到的内容来看,.tbss 只是用于线程本地存储的.bss 部分(即分配的内存暂存空间,并未真正映射到物理文件中)。是不是.tbss部分太特别了,可以和其他部分重叠? .init_array、.fini_array和.jcr是不是就这么没用(比如TLS相关的代码运行后就不需要了),所以可以被bss覆盖?或者它是某种错误?
基本上,如果我尝试在我的应用程序中读取地址 0x6b4020,我会读取和写入什么? .tbss 内容还是 .init_array 指针?为什么?
【问题讨论】:
-
很可能我不会帮助你。但也许您应该阅读 AMD64 gcc ABI 参考。 x86-64.org/documentation/abi.pdf。我记得对线程本地存储的访问是由段寄存器 FS 或 GS “前缀”的。如果我没记错的话,你的帖子将解决 FS:0x6b4020。
-
确实,我记得在某处读到,线程本地存储将使用 FS 段前缀操作,这纯粹是 glibc 的约定(不是平台 ABI,不是 SysV 调用约定的一部分)...要去试试阅读 Drepper 关于 TLS 的手册...
-
该部分被标记为 NOBITS,这意味着 ELF 文件中没有与之关联的数据,只有大小。对于 NOBITS 部分,偏移字段是正式填写的。这种节的另一个例子是
.bss,零初始化数据节。只要我们知道该部分是零初始化的,就不需要在文件中实际存储零,知道大小就足够了。 -
@AndreyChernyakhovskiy:我对无意义的偏移(即 0xb4020)没有任何问题,我对重叠 in-memory 地址范围(即 0x6b4020)有问题。
标签: gcc ld static-linking elf thread-local-storage