Joh*_*itb 68
自从我和ELF合作以来已经有一段时间了.但我想我还记得这些东西.不,它实际上不包含那些零.如果您查看ELF文件程序标题,那么您将看到每个标题有两个数字:一个是文件中的大小.另一个是在虚拟内存(readelf -l ./a.out)中分配的部分大小:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00454 0x00454 R E 0x1000
LOAD 0x000454 0x08049454 0x08049454 0x00104 0x61bac RW 0x1000
DYNAMIC 0x000468 0x08049468 0x08049468 0x000d0 0x000d0 RW 0x4
NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
Run Code Online (Sandbox Code Playgroud)
类型的标头LOAD是在加载文件以执行时复制到虚拟内存中的标头.其他标头包含其他信息,例如所需的共享库.正如你看到的,FileSize而MemSiz显著为包含头不同bss部分(第二LOAD其一):
0x00104 (file-size) 0x61bac (mem-size)
Run Code Online (Sandbox Code Playgroud)
对于此示例代码:
int a[100000];
int main() { }
Run Code Online (Sandbox Code Playgroud)
ELF规范说,mem-size大于文件大小的段的一部分只是在虚拟内存中用零填充.第二个LOAD标题的段到节映射如下所示:
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
Run Code Online (Sandbox Code Playgroud)
所以还有其他一些部分.对于C++构造函数/析构函数.Java也是如此.然后它包含该.dynamic部分的副本和其他对动态链接有用的东西(我相信这是包含所需的共享库以及其他东西的地方).之后.data包含初始化全局变量和局部静态变量的部分.最后,.bss显示该部分,在加载时由零填充,因为文件大小不会覆盖它.
顺便说一下,您可以使用-M链接器选项查看将要放置特定符号的输出节.对于gcc,您-Wl,-M可以将选项放到链接器中.上面的例子显示了a在内部分配.bss.它可以帮助您验证未初始化的对象是否真正进入,.bss而不是其他地方:
.bss 0x08049560 0x61aa0
[many input .o files...]
*(COMMON)
*fill* 0x08049568 0x18 00
COMMON 0x08049580 0x61a80 /tmp/cc2GT6nS.o
0x08049580 a
0x080ab000 . = ALIGN ((. != 0x0)?0x4:0x1)
0x080ab000 . = ALIGN (0x4)
0x080ab000 . = ALIGN (0x4)
0x080ab000 _end = .
Run Code Online (Sandbox Code Playgroud)
默认情况下,GCC在COMMON部分保留未初始化的全局变量,以便与旧编译器兼容,允许在程序中定义两次全局变量而不会出现多个定义错误.使用-fno-common使GCC使用对象文件的.bss段(未作出最终链接的可执行文件的差别,因为当你看到它会进入一个的.bss输出部分无论如何,这是由控制链接脚本.它显示与ld -verbose).但这不应该吓到你,这只是一个内部细节.请参阅gcc的联机帮助页.
D.S*_*ley 21
.bssELF文件中的部分用于静态数据,该数据未以编程方式初始化,但保证在运行时设置为零.这是一个可以解释差异的小例子.
int main() {
static int bss_test1[100];
static int bss_test2[100] = {0};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下bss_test1放入,.bss因为它是未初始化的.bss_test2然而,它.data与一堆零一起放入段中.运行时加载器基本上为.bss任何用户区代码开始执行之前分配保留的空间量并将其清零.
您可以使用看出差别objdump,nm或类似的实用程序:
moozletoots$ objdump -t a.out | grep bss_test
08049780 l O .bss 00000190 bss_test1.3
080494c0 l O .data 00000190 bss_test2.4
Run Code Online (Sandbox Code Playgroud)
这通常是嵌入式开发人员遇到的第一个惊喜之一......永远不会将静态初始化为零.运行时加载器(通常)负责处理.只要明确初始化任何内容,就会告诉编译器/链接器将数据包含在可执行映像中.
| 归档时间: |
|
| 查看次数: |
25201 次 |
| 最近记录: |