C中的bss段

时间:2012-10-09 10:52:12

标签: c memory-management data-segment

在问题“Regarding the bss segment and data segment in Unix”的答案之一中,我看到对bss的解释如下:

  

Bss很特殊:.bss对象不占用目标文件中的任何空间,并且通过将未特别初始化的所有符号分组在一起,可以很容易地将它们一次归零。

但是当我在目标文件上使用size时,会生成代码:

#include <stdio.h>
int uninit_global_var;
int init_global_var=5;

int main()
{
   int local_var;
   return 0;
}

我有以下

text    data      bss    dec     hex filename
1231     280      12    1523     5f3 a.out

并根据具有全局范围的未初始化数据成员查看bss的增长情况。那么有人可以证明上述陈述的合理性吗?

4 个答案:

答案 0 :(得分:9)

如果你删除stdio.h,你的输出可能会更有意义。让我们忽略那个库,因为它包含内部变量。

在您的具体情况下,会发生以下情况:

int uninit_global_var;

由于这是在文件范围中分配的变量,其静态存储持续时间,就像声明为static的任何变量一样。 C标准要求如果程序员未明确初始化具有静态存储持续时间的变量,则在程序启动之前必须将其设置为零。所有此类变量都放在.bss段中。

int init_global_var=5;

此变量也在文件范围内分配,因此它也将具有静态存储持续时间。但在这种情况下,它由程序员初始化。 C标准要求在程序启动之前将这些变量设置为给定的值。这些变量放在.data段中。

   int local_var;

此变量具有自动存储持续时间(本地)。编译器很可能会优化掉这个变量,因为它没有任何用途。但我们假设这种优化不会发生。然后,变量将在运行时分配,当它所驻留的范围(块)执行时,一旦该范围被finsihed(它超出范围)就停止存在。它将在堆栈或CPU寄存器中分配。换句话说,在链接时,这个变量只作为程序代码存在,以某些汇编指令的形式表示“在堆栈上推送一个int”然后“从堆栈中弹出一个int”。

如何初始化这些不同类型的变量取决于系统。但通常会在调用main之前由编译器注入一些代码。这是一种过度简化,但出于教育学的考虑,你可以想象你的程序实际上是这样的:

bss
{
  int uninit_global_var;
}

data
{
  int init_global_var;
}

rodata
{
  5;
}


int start_of_program (void) // called by OS
{
  memset(bss, 0, bss_size);
  memcpy(data, rodata, data_size);

  return main(); 
}

数据:4 BSS:4

具有真正非易失性存储器的嵌入式系统将完全像上述代码一样工作,而基于RAM的系统可能以不同方式解决数据初始化部分。 bss在所有系统上都是一样的。


您可以通过运行以下程序轻松验证它们是否存储在不同的细分中:

char uninit1;
char uninit2;
char init1 = 1;
char init2 = 2;

int main (void)
{
  char local1 = 1;
  char local2 = 2;

  printf("bss\t%p\t%p\n", &uninit1, &uninit2);
  printf("data\t%p\t%p\n", &init1, &init2);
  printf("auto\t%p\t%p\n", &local1, &local2);
}

您将看到“uninit”变量在相邻地址处分配,但在与其他变量不同的地址处分配。与“init”变量相同。 “本地”变量可以在任何地方分配,这样你就可以得到任何一种奇怪的地址。

答案 1 :(得分:5)

我肯定不知道答案,但我的猜测是:

bss段的SIZE位于目标文件中,并按大小显示 - &gt;毕竟,它必须被分配。

但是当bss段增长时,目标文件不会增长。

答案 2 :(得分:2)

a.out可能不是一个目标文件,它可能是一个ELF - 完整的可执行文件。可重定位的对象(通常名为 name .o)是链接发生之​​前的中间文件。请参阅gcc的-c选项。

答案 3 :(得分:2)

bss段增长,但您的二进制文件中不需要此段(请参阅objcopy)。

所以最终如果你把这段代码放到某种ROM中,它就不会占用空间,但需要RAM中的空间(以及将它初始化为0的代码)。