我想在c语言中理解带有‘SIZE’命令的内存存储段.我分别做了以下几点:


File1.c

#include <stdio.h>
int main(void) {
    return 0;
}
  • gcc -o size1 File1.c
  • size size1.exe
text    data     bss     dec     hex filename
7446    1404     244   12708    24b4 ./size1.exe

File2.c

#include <stdio.h>
int glb; /* Uninitialized variable stored in bss*/
int main(void) {
    return 0;
}
  • gcc -o size2 File2.c
  • size size2.exe
text    data     bss     dec     hex filename
7446    1404     244   12708    24b4 ./size2.exe

File2.c的规模中,我预计bss个细分市场会增加,但没有改变.为什么会发生这种事?

已添加全局变量,但BSS段未增加


Edit :

*使用对象文件而不是.exe解决了我的问题,但现在.bss增加了16个而不是4个

Question evolved to why .bss increase of 16 instead of 4?

推荐答案

通常的原因是"结盟".程序中可能存在需要与一定字节数的倍数对齐的对象,这可能需要插入填充(已分配但未使用的字节).新添加的对象可能碰巧被放置在原本用于填充的区域中,在这种情况下,它实际上不会增加该部分的整体大小.

举个简单的例子,假设您的原始程序在.bss节中有两个对象(例如,由启动代码使用),一个需要2字节对齐的2字节对象my_short,以及一个需要8字节对齐的8字节对象my_long.链接器可能碰巧将它们放在内存中,如下所示:

0x0 - 0x1: my_short
0x2 - 0x7: (padding)
0x8 - 0xf: my_long

总共使用了16个字节,包括6个字节的填充.

现在添加一个4字节的新对象glb,需要4字节对齐.根据链接器处理其目标文件的顺序,它可以放在my_short之后但my_long之前.在这种情况下,内存映射可能如下所示:

0x0 - 0x1: my_short
0x2 - 0x3: (padding)
0x4 - 0x7: glb
0x8 - 0xf: my_long

总数仍然是16字节,但现在只有2字节的填充.

您可以使用-Wl,-M选项(这是一个选项,其中有一个逗号,没有空格)来 for each 版本发出一个链接器映射,您应该能够看到它的发生.


在我的系统上,两个版本都有一个8字节的.bss部分.ld使用的链接器脚本(可以使用-Wl,--verbose打印)在.bss的末尾包含ALIGN指令,因此.bss总是以8字节的倍数结束.(脚本文件中有一个Fixme注释,表明其中一个程序员不确定他们这样做的原因或是否真的有必要这样做.)

除了glb之外,.bss中只有1个字节(由启动代码使用),因此后面要么是7个字节的填充,要么是3个字节的填充,然后是glb.

C++相关问答推荐

获取二维数组的最大元素

为什么在C中二维字符数组会有这样的行为?

自定义应用程序上的日志(log)轮换问题

C lang:当我try 将3个或更多元素写入数组时,出现总线错误

为什么即使在强制转换时,此代码也会溢出?

是否定义了此函数的行为?

试图创建一个基本的Word克隆,但遇到了障碍

C语言中MPI发送接收字符串时出现的分段错误

CS50判断灯泡运动的问题,判断时多出一个灯泡,但不在终端上

如何在C宏定义中包含双引号?

如何在C中定义指向函数的指针并将该指针赋给函数?

c程序,让用户输入两类数字,并给出输出用户输入多少个数字

带有数组指针的 struct 在print_stack()函数中打印随机数

在下面的C程序中,.Ap0是如何解释的?

在printf()中用%.*S格式填充长度为0的字符串是否会调用任何UB?如果是,是哪一个?

无算术运算符和循环的二进制乘法

为什么我在我的代码中得到错误和退出代码-1073741819(0xC0000005),但如果我添加了一个不相关的打印语句,它仍然有效?

C程序printf在getchar while循环后不工作

在C中,为什么这个带有递增整数的main函数从不因溢出而崩溃?

根据输入/输出将 C 编译过程分为预处理、编译、汇编和链接步骤