零初始化的结构不会出现在内存中
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
被“忽略”了?
【问题讨论】:
它本身并没有被忽略,请尝试使用readelf
或elfdump
- 编译器很可能会保留空间,但由于它已归零,因此不将其存储在磁盘上无法证实我的假设在这台机器上,但在大多数可执行格式中都有类似的约定
用于链接的默认链接器脚本会将零初始化数据放在 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把各个位清零???