了解 C 中数据 bss 段的大小命令

Posted

技术标签:

【中文标题】了解 C 中数据 bss 段的大小命令【英文标题】:understanding size command for data bss segment in C 【发布时间】:2015-05-31 02:32:02 【问题描述】:

我收到来自size 命令的意外输出。

Afaik 初始化了存储在 data 段中的全局和静态变量,未初始化并初始化为 0 存储在 bss 段中的全局/静态变量。

printf("%d",sizeof(int));int 的大小设为 4。但是,bssdata 段并没有相应地增加到 4。

#include <stdio.h>
int main()

    return 0;


C:\Program Files (x86)\Dev-Cpp\MinGW64\bin>size memory-layout.exe
   text    data     bss     dec     hex filename
  10044    2292    2512   14848    3a00 memory-layout.exe

#include <stdio.h>
int g; //uninitialised global variable so, stored in bss segment
int main()

    return 0;


C:\Program Files (x86)\Dev-Cpp\MinGW64\bin>size memory-layout.exe
   text    data     bss     dec     hex filename
  10044    2292    2528   14864    3a10 memory-layout.exe

为什么bss 增加了 16 (2528 - 2512) 而不是 4? (在上面的代码中)

#include <stdio.h>
int g=0; //initialised to 0 so, stored in bss segment
int main()

    return 0;


C:\Program Files (x86)\Dev-Cpp\MinGW64\bin>size memory-layout.exe
   text    data     bss     dec     hex filename
  10044    2292    2512   14848    3a00 memory-layout.exe

尽管使用了全局变量,bss 没有增量。这是为什么呢?

 #include <stdio.h>
int main()
   static int g; //should be on bss segment
    return 0;


C:\Program Files (x86)\Dev-Cpp\MinGW64\bin>size memory-layout.ex
   text    data     bss     dec     hex filename
  10044    2292    2512   14848    3a00 memory-layout.exe

尽管使用了静态变量,bss 段没有增加,为什么?

我还有一个问题,dec 在这里代表什么?

【问题讨论】:

使用odnm 命令列出对象/可执行文件、它们的部分和它们的部分。 @a3f 有什么意义 查看链接器映射以了解这些变量实际的去向。看起来您的链接器正在以 16 字节增量而不是 4 字节增量来增加节的大小。您可以通过分阶段执行int a; int b; int c; int d; int e; 并注意它的大小何时增加来对此进行试验。 int g = 0; 案例似乎表明它正在进入 .data 并且没有增加,因为我们刚刚看到已经有空间了。 还要记住,如果编译器意识到变量没有被使用,它们可能会被优化掉;这可能发生在案例 2 和 3 中。 案例 1:未初始化的全局:值在 BSS 中。链接器在 BSS 中以 16 字节边界分配空间。因此,BSS 大小增加了 16。 情况 2:初始化为零:编译器不将此视为默认初始化的情况,并将其与其他已初始化的全局变量一起放入数据段中。因此,BSS 情况 3 没有增加:函数内的静态变量。编译器知道你没有使用这个变量。 BSS 中没有分配空间。在以前的情况下,由于这些是全局变量,编译器无法对其进行优化。 dec : 总大小 = 文本 + bss + 十进制数据。 【参考方案1】:

首先要考虑的是内存对齐。可以填充变量和部分以使它们位于地址边界上。在第二个示例中,您看到比第一个增加了 16,这表明填充 16 字节边界(2512 / 16 = 157、2528 / 16 = 158)。这完全取决于实现。

就 C 而言,第二个示例与第三个示例不同,因为编译器无法知道 int g 是一个定义还是仅仅是另一个文件中定义的整数的声明(它可以是任何值)。它为链接器留下了一个参考来处理,这可能会导致填充的差异。

在第三个示例中,g 被显式定义并设置为 0,因此编译器知道将其放入 BSS 部分。

可以用我的系统生成的程序集来证明这一点:

int g(在这种情况下没有定义 BSS 部分)

.comm   g,4,4

这是链接器处理符号的指令,因为编译器无法完全确定如何处理它。

int g = 0

    .bss
    .align 4
    .type   g, @object
    .size   g, 4
g:
    .zero   4

这里编译器确切地知道要做什么,因此为符号定义了一个 BSS 部分。

在我的情况下,链接器以相同的方式解决这些问题。两者都放置在相同地址的 BSS 部分中,因此 BSS 大小没有差异。您可以使用 nm 之类的实用程序检查布局。

nm -n file2 file3 | grep g$

000000000060103c B g
000000000060103c B g

即在这个系统上g 在同一个地址。或者,使用调试器:

(gdb) info symbol 0x60103c
g in section .bss of /tmp/file2

还请注意,在最后一个示例中,可以优化变量,因为它具有内部链接。

对于dec,它只是十进制部分的总和。

【讨论】:

【参考方案2】:

这是来自 linux 上的 gcc:

No Variable
   text    data     bss     dec     hex filename
    915     248       8    1171     493 none.out
Uninitialized Global
   text    data     bss     dec     hex filename
    915     248      12    1175     497 u_g.out
Initialized Global to 123
   text    data     bss     dec     hex filename
    915     252       8    1175     497 i_g.out
Initialized Local to 124
   text    data     bss     dec     hex filename
    915     252       8    1175     497 i_l.out
Initialized Global to 0
   text    data     bss     dec     hex filename
    915     248      12    1175     497 i_g_0.out
Initialized Local to 0
   text    data     bss     dec     hex filename
    915     248      12    1175     497 i_l_0.out

这是来自 Windows 上的 mingw64:

No Variable
   text    data     bss     dec     hex filename
   3173    1976     448    5597    15dd none.out
Uninitialized Global
   text    data     bss     dec     hex filename
   3173    1976     464    5613    15ed u_g.out
Initialized Global to 123
   text    data     bss     dec     hex filename
   3173    1976     448    5597    15dd i_g.out
Initialized Local to 124
   text    data     bss     dec     hex filename
   3173    1976     448    5597    15dd i_l.out
Initialized Global to 0
   text    data     bss     dec     hex filename
   3173    1976     480    5629    15fd i_g_0.out
Initialized Local to 0
   text    data     bss     dec     hex filename
   3173    1976     480    5629    15fd i_l_0.out

因此,尽管我对这个问题没有最终答案(不适合发表评论),但结果让我怀疑 Windows 和/或 MinGW 的可执行文件格式(即不是 gcc)。

【讨论】:

【参考方案3】:

BSS 仅包含未显式初始化的静态和全局值。即使您将其显式初始化为与未显式初始化时将被初始化的值相同的值,但显式初始化的事实意味着它不属于 bss。

【讨论】:

这是不正确的。初始化为零的数据可能在 BSS 部分。 @teppic,即使它确实可能在 BSS 段中,事实上它显式初始化(​​甚至为 0 ) 表示它不需要在 BSS 段中。可以说它必须在 BSS 中的唯一情况是它显式初始化全局静态。 这取决于实现,它不必为任何事情使用 BSS。 这个怎么样:如果它有 BSS 并且它在 BSS 中存储未初始化的数据(这是 BSS 的用途),那么在 BSS 中存储初始化为 0 的数据是一种可选的优化。 问题是它都是可选的,没有标准,它是由实现定义的(硬件和编译器)。 BSS 更多的是关于存储应该为零的数据,而不必在二进制文件中分配空间。

以上是关于了解 C 中数据 bss 段的大小命令的主要内容,如果未能解决你的问题,请参考以下文章

Linux常用的几个vi小命令

linux的各种小命令和目录

实用小命令

Linux 小命令

每天一个linux小命令之--ls

Linux小命令date详解