C语言 C 中 data 部分和 bss 部分的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16557677/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 06:19:59  来源:igfitidea点击:

Difference between data section and the bss section in C

cunix

提问by Angus

When checking the disassembly of the object file through the readelf, I see the data and the bss segments contain the same offset address. The data section will contain the initialised global and static variables. BSS will contain un-initialised global and static variables.

通过readelf检查目标文件的反汇编时,看到data和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 }

output:

输出:

   SSS:~$ size a.out 
   text    data     bss     dec     hex filename
   1311     260       8    1579     62b a.out

Here in the above program I don't have any un-initialised data but the BSS has occupied 8 bytes. Why does it occupy 8 bytes? Also when I disassemble the object file,

在上面的程序中,我没有任何未初始化的数据,但 BSS 已占用 8 个字节。为什么要占用8个字节?此外,当我反汇编目标文件时,

EDITED :

编辑:

  [ 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

data, rodata and bss has the same offset address. Does it mean the rodata, data and bss refer to the same address? Do Data section, rodata section and the bss section contain the data values in the same address, if so how to distinguish the data section, bss section and rodata section?

data、rodata 和 bss 具有相同的偏移地址。这是否意味着rodata、data和bss指的是同一个地址?数据段、rodata段和bss段是否包含同一地址中的数据值,如果是,如何区分数据段、bss段和rodata段?

回答by Jonathon Reinhart

The .bsssection is guaranteed to be all zeros when the program is loaded into memory. So any global data that is uninitialized, or initialized to zero is placed in the .bsssection. For example:

.bss当程序加载到内存中时,该部分保证全为零。因此,任何未初始化或初始化为零的全局数据都放置在该.bss部分中。例如:

static int g_myGlobal = 0;     // <--- in .bss section

The nice part about this is, the .bsssection data doesn't have to be included in the ELF file on disk (ie. there isn't a whole region of zeros in the file for the .bsssection). Instead, the loader knows from the section headers how much to allocate for the .bsssection, and simply zero it out before handing control over to your program.

关于这一点的好处是,.bss节数据不必包含在磁盘上的 ELF 文件中(即,该.bss节的文件中没有整个零区域)。取而代之的是,加载器从段头中知道要为该.bss段分配多少,并在将控制权移交给您的程序之前简单地将其清零。

Notice the readelfoutput:

注意readelf输出:

[ 3] .data PROGBITS 00000000 000110 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000110 000000 00 WA 0 0 4

.datais marked as PROGBITS. That means there are "bits" of program data in the ELF file that the loader needs to read out into memory for you. .bsson the other hand is marked NOBITS, meaning there's nothing in the file that needs to be read into memory as part of the load.

.data被标记为PROGBITS。这意味着 ELF 文件中有“位”程序数据,加载程序需要为您读取到内存中。.bss另一方面,标记为NOBITS,这意味着文件中没有任何内容需要作为加载的一部分读入内存。



Example:

例子:

// bss.c
static int g_myGlobal = 0;

int main(int argc, char** argv)
{
   return 0;
}

Compile it with $ gcc -m32 -Xlinker -Map=bss.map -o bss bss.c

编译它 $ gcc -m32 -Xlinker -Map=bss.map -o bss bss.c

Look at the section headers with $ readelf -S bss

查看部分标题 $ 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
   :

Now we look for our variable in the symbol table: $ readelf -s bss | grep g_myGlobal

现在我们在符号表中查找我们的变量: $ readelf -s bss | grep g_myGlobal

37: 08049654     4 OBJECT  LOCAL  DEFAULT   25 g_myGlobal

Note that g_myGlobalis shown to be a part of section 25. If we look back in the section headers, we see that 25 is .bss.

请注意,g_myGlobal它显示为第 25 节的一部分。如果我们回顾一下节标题,我们会看到 25 是.bss



To answer your real question:

回答你真正的问题:

Here in the above program I dont have any un-intialised data but the BSS has occupied 8 bytes. Why does it occupy 8 bytes ?

在上面的程序中,我没有任何未初始化的数据,但 BSS 已占用 8 个字节。为什么它占用8个字节?

Continuing with my example, we look for any symbol in section 25:

继续我的例子,我们在第 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

The third column is the size. We see our expected 4-byte g_myGlobal, and this 1-byte completed.5745. This is probably a function-static variable from somewhere in the C runtime initialization - remember, a lot of "stuff" happens before main()is ever called.

第三列是尺寸。我们看到了我们预期的 4-byteg_myGlobal和这个 1-byte completed.5745。这可能是 C 运行时初始化中某个地方的函数静态变量 - 请记住,在main()调用之前发生了很多“东西” 。

4+1=5 bytes. However, if we look back at the .bsssection header, we see the last column Alis 4. That is the section alignment, meaning this section, when loaded, will always be a multiple of 4 bytes. The next multiple up from 5 is 8, and that's why the .bsssection is 8 bytes.

4+1=5 个字节。但是,如果我们回头看.bss段标题,我们会看到最后一列Al是 4。这是段对齐方式,这意味着该段在加载时将始终是 4 字节的倍数。从 5 开始的下一个倍数是 8,这就是该.bss部分是 8 个字节的原因。



AdditionallyWe can look at the map file generated by the linker to see what object files got placed where in the final output.

此外,我们可以查看链接器生成的映射文件,以查看哪些目标文件放置在最终输出中的位置。

.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

Again, the third column is the size.

同样,第三列是大小。

We see 4 bytes of .bsscame from /tmp/ccKF6q1g.o. In this trivial example, we know that is the temporary object file from the compilation of our bss.c file. The other 1 byte came from crtbegin.o, which is part of the C runtime.

我们看到 4 个字节的.bss来自/tmp/ccKF6q1g.o. 在这个简单的例子中,我们知道这是编译我们的 bss.c 文件的临时目标文件。另一个 1 字节来自crtbegin.o,它是 C 运行时的一部分。



Finally, since we know that this 1 byte mystery bss variable is from crtbegin.o, and it's named completed.xxxx, it's real name is completedand it's probably a static inside some function. Looking at crtstuff.cwe find the culprit: a static _Bool completedinside of __do_global_dtors_aux().

最后,因为我们知道这个 1 字节的神秘 bss 变量来自crtbegin.o,并且它的名字是completed.xxxx,它的真实名称是completed并且它可能是某个函数内部的静态变量。纵观crtstuff.c我们找到罪魁祸首:一个static _Bool completed__do_global_dtors_aux()

回答by Basile Starynkevitch

By definition, the bsssegment takes some place in memory (when the program starts) but don't need any disk space. You need to define some variable to get it filled, so try

根据定义,bss段在内存中占据某个位置(当程序启动时)但不需要任何磁盘空间。你需要定义一些变量来填充它,所以试试

int bigvar_in_bss[16300];
int var_in_data[5] = {1,2,3,4,5};

Your simple program might not have any data in .bss, and shared libraries (like libc.so) may have "their own .bss"

您的简单程序中可能没有任何数据.bss,共享库(如libc.so)可能有“自己的.bss

File offsets and memory addresses are not easily related.

文件偏移量和内存地址不容易相关。

Read more about the ELFspecification, also use /proc/(eg cat /proc/self/mapswould display the address space of the catprocess running that command). Read also proc(5)

阅读有关ELF规范的更多信息,也可以使用/proc/(例如,cat /proc/self/maps将显示cat运行该命令的进程的地址空间)。另请阅读proc(5)