零初始化的结构不会出现在内存中

Posted

技术标签:

【中文标题】零初始化的结构不会出现在内存中【英文标题】:Zero-initialized struct not appear in memory 【发布时间】:2018-03-27 03:48:44 【问题描述】:

我正在学习汇编,令我惊讶的是,零初始化的结构不会占用内存。 我的代码就是这样的。

// in file a.cpp
#include <stdint.h>
struct Bar 
    char filename[8];
    // ignore members here
    uint32_t filesize;
__attribute__((packed));

typedef struct FAT_ITEM FAT_ITEM;

Bar bar1 = 
    "null",0
;
Bar bar2 = 
    "",0
;

然后我编译代码

gcc -march=i386 -m16 -mpreferred-stack-boundary=2 -ffreestanding -O0 a.cpp a.o
ld -melf_i386 -N --oformat binary -o a.bin a.o

但是,当我使用 dd 读取 a.bin 中的二进制文件时,我看到了

00000000: 6e75 6c6c 0000 0000 0000 0000            null........
(END)

bar2 没有出现在内存中。 32 位零来自bar1.filesize(END) 紧随其后。

我正在学习 16 位 x86 汇编,所以编译选项可能很奇怪。但我认为他们不会导致这个问题。

谁能帮我解释一下为什么bar2被“忽略”了?

【问题讨论】:

它本身并没有被忽略,请尝试使用readelfelfdump - 编译器很可能会保留空间,但由于它已归零,因此不将其存储在磁盘上无法证实我的假设在这台机器上,但在大多数可执行格式中都有类似的约定 用于链接的默认链接器脚本会将零初始化数据放在 BSS 部分。默认链接描述文件的 BSS 部分将在物理写入文件后将其放置在内存中。如果您正在编写自己的操作系统(或引导加载程序)并自己将 a.bin 加载到内存中,则由您将 BSS 部分初始化为零。 注意:您将问题标记为 C,但您将其编译为 C++。 【参考方案1】:

将零初始化的东西放入 BSS 的编译器,which the default linker script doesn't allocate space for in a flat binary;它在其他部分结束后开始。

在 C 代码运行之前在启动时自行归零,或禁用编译器对 BSS 的使用(例如 -fno-zero-initialized-in-bss

你可以看gcc -S的输出;请注意.lcomm or .comm directives,它为所有零初始化静态/全局变量保留 BSS 空间。在编译普通的 Linux 可执行文件时,您不希望在可执行文件中显式存储大量的零数组。

请参阅https://gcc.gnu.org/ml/gcc-help/2007-07/msg00097.html 进行一些讨论,例如如果您不想编写在启动时运行的零初始​​化循环,则可以使用__attribute__ 将实际上需要进行零初始化的数组放入不同的部分。然后,您可以在 BSS 中保留一些根本不需要初始化的数组,但在二进制文件中将空间用于在其他需要它的东西上显式为零。

【讨论】:

以上是关于零初始化的结构不会出现在内存中的主要内容,如果未能解决你的问题,请参考以下文章

C++中,类内的成员变量自动初始化为零吗,而全局变量随意赋值

C语言中,使用一个结构体之前,要用memset把各个位清零???

bss 概念

为啥我的内核的共享内存似乎初始化为零?

内存数据库H2中的Spring Boot在初始化时不会从文件中加载数据

结构零初始化方法