通过readelf检查目标文件的反汇编时,我看到数据和bss段包含相同的偏移地址.数据部分将包含初始化的全局变量和静态变量.BSS将包含非主动化的全局变量和静态变量.
1 #include<stdio.h>
2
3 static void display(int i, int* ptr);
4
5 int main(){
6 int x = 5;
7 int* xptr = &x;
8 printf("\n In main() program! \n");
9 printf("\n x address : 0x%x x value : %d \n",(unsigned int)&x,x);
10 printf("\n xptr points to : 0x%x xptr value : %d \n",(unsigned int)xptr,*xptr);
11 display(x,xptr);
12 return 0;
13 }
14
15 void display(int y,int* yptr){
16 char var[7] = "ABCDEF";
17 printf("\n In display() function \n");
18 printf("\n y value : %d y address : 0x%x \n",y,(unsigned int)&y);
19 printf("\n yptr points to : 0x%x yptr value : %d \n",(unsigned int)yptr,*yptr);
20 }
Run Code Online (Sandbox Code Playgroud)
输出:
SSS:~$ size a.out
text data bss dec hex filename
1311 260 8 1579 62b a.out
Run Code Online (Sandbox Code Playgroud)
在上面的程序中,我没有任何非本地化数据,但BSS占用了8个字节.为什么它占用8个字节?当我反汇编目标文件时,
编辑:
[ 3] .data PROGBITS 00000000 000110 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000110 000000 00 WA 0 0 4
[ 5] .rodata PROGBITS 00000000 000110 0000cf 00 A 0 0 4
Run Code Online (Sandbox Code Playgroud)
data,rodata和bss具有相同的偏移地址.这是指rodata,data和bss是指同一个地址吗?数据部分,rodata部分和bss部分是否包含相同地址的数据值,如果是这样,如何区分数据部分,bss部分和rodata部分?
Jon*_*art 43
.bss当程序加载到内存中时,该部分保证全为零.因此,任何未初始化或初始化为零的全局数据都将放在该.bss部分中.例如:
static int g_myGlobal = 0; // <--- in .bss section
Run Code Online (Sandbox Code Playgroud)
关于这一点的好处是,.bss部分数据不必包含在磁盘上的ELF文件中(即,该.bss部分的文件中没有整个零区域).相反,加载器从节标题中知道为该节分配多少.bss,并在将控制权交给您的程序之前简单地将其清零.
注意readelf输出:
[ 3] .data PROGBITS 00000000 000110 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000110 000000 00 WA 0 0 4
Run Code Online (Sandbox Code Playgroud)
.data被标记为PROGBITS.这意味着ELF文件中存在程序数据的"位",加载程序需要为您读入内存..bss另一方面,标记了NOBITS,这意味着文件中没有任何内容需要作为负载的一部分读入内存.
例:
// bss.c
static int g_myGlobal = 0;
int main(int argc, char** argv)
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
用它编译 $ gcc -m32 -Xlinker -Map=bss.map -o bss bss.c
查看部分标题 $ readelf -S bss
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
:
[13] .text PROGBITS 080482d0 0002d0 000174 00 AX 0 0 16
:
[24] .data PROGBITS 0804964c 00064c 000004 00 WA 0 0 4
[25] .bss NOBITS 08049650 000650 000008 00 WA 0 0 4
:
Run Code Online (Sandbox Code Playgroud)
现在我们在符号表中查找变量: $ readelf -s bss | grep g_myGlobal
37: 08049654 4 OBJECT LOCAL DEFAULT 25 g_myGlobal
Run Code Online (Sandbox Code Playgroud)
请注意,g_myGlobal它显示为第25节的一部分.如果我们回头看部分标题,我们会看到25是.bss.
回答你的真实问题:
在上面的程序中,我没有任何非本地化数据,但BSS占用了8个字节.为什么它占用8个字节?
继续我的例子,我们在第25节中寻找任何符号:
$ readelf -s bss | grep 25
9: 0804825c 0 SECTION LOCAL DEFAULT 9
25: 08049650 0 SECTION LOCAL DEFAULT 25
32: 08049650 1 OBJECT LOCAL DEFAULT 25 completed.5745
37: 08049654 4 OBJECT LOCAL DEFAULT 25 g_myGlobal
Run Code Online (Sandbox Code Playgroud)
第三列是大小.我们看到了我们预期的4字节g_myGlobal和这个1字节completed.5745.这可能是C运行时初始化中某个地方的函数静态变量 - 记住,在main()调用之前会发生很多"东西" .
4 + 1 = 5个字节.但是,如果我们回头查看.bss节标题,我们会看到最后一列Al是4.这是节对齐,这意味着此节在加载时将始终是4个字节的倍数.从5开始的下一个倍数是8,这就是该.bss部分为8个字节的原因.
另外,我们可以查看链接器生成的映射文件,以查看最终输出中放置的对象文件.
.bss 0x0000000008049650 0x8
*(.dynbss)
.dynbss 0x0000000000000000 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o
*(.bss .bss.* .gnu.linkonce.b.*)
.bss 0x0000000008049650 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o
.bss 0x0000000008049650 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crti.o
.bss 0x0000000008049650 0x1 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtbegin.o
.bss 0x0000000008049654 0x4 /tmp/ccKF6q1g.o
.bss 0x0000000008049658 0x0 /usr/lib/libc_nonshared.a(elf-init.oS)
.bss 0x0000000008049658 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtend.o
.bss 0x0000000008049658 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crtn.o
Run Code Online (Sandbox Code Playgroud)
同样,第三列是大小.
我们看到4个字节.bss来自/tmp/ccKF6q1g.o.在这个简单的例子中,我们知道这是来自bss.c文件编译的临时目标文件.另外1个字节来自crtbegin.o,它是C运行时的一部分.
最后,因为我们知道这个1字节的神秘bss变量来自crtbegin.o,并且它被命名completed.xxxx,它的真实名称是,completed并且它可能是某个函数内部的静态.看着crtstuff.c我们找到了罪魁祸首:static _Bool completed内心__do_global_dtors_aux().
根据定义,bss段在内存中占据某个位置(当程序启动时),但不需要任何磁盘空间。您需要定义一些变量来填充它,所以尝试
int bigvar_in_bss[16300];
int var_in_data[5] = {1,2,3,4,5};
Run Code Online (Sandbox Code Playgroud)
您的简单程序可能在 中没有任何数据.bss,并且共享库(如libc.so)可能有“它们自己的.bss”
文件偏移量和内存地址不容易关联。
阅读有关ELF规范的更多信息,也可以使用/proc/(例如,显示运行该命令的进程cat /proc/self/maps的地址空间)。cat另请阅读proc(5)