gpt4 book ai didi

c - 为什么使用 .data 而不是在 .bss 中保留空间并在运行时初始化,用于 assembly/C 中的变量?

转载 作者:可可西里 更新时间:2023-11-01 11:51:21 25 4
gpt4 key购买 nike

首先:我知道有很多网页(包括stackoverflow上的讨论)讨论了.bss和.data在数据声明方面的区别,但是我有一个具体的问题,我没有找到不幸的是,这些页面上的答案,所以我在这里问 :-)。

我是汇编的初学者,所以如果这个问题很愚蠢,我深表歉意:-)。

我正在 x86 64 位 linux 操作系统上学习汇编(但我认为我的问题更笼统,可能不特定于操作系统/架构)。

我发现 .bss 和 .data 部分的定义有点奇怪。我总是可以在 .bss 中声明一个变量,然后在我的代码(.text 部分)中移动这个变量中的值,对吗?那么为什么我要在 .data 部分声明一个变量,如果我知道在这个部分声明的变量会增加我的可执行文件的大小?

我也可以在 C 编程的上下文中问这个问题:为什么我要初始化我的变量,当我声明它时声明它未初始化然后在我的代码开头为其赋值更有效?

我想我的内存管理方法很幼稚而且不正确,但我不明白为什么。

最佳答案

.bss 是放置零初始化静态数据的地方,例如 C int x;(在全局范围内)。对于静态/全局(静态存储类)1,这与 int x = 0; 相同。

.data 是你放置非零初始化静态数据的地方,比如 int x = 2; 如果你把它放在 BSS 中,您需要一个运行时静态“构造函数”来初始化 BSS 位置。就像 C++ 编译器对 static const int prog_starttime = __rdtsc(); 所做的一样。 (尽管它是 const,但初始化器不是编译时常量,因此它不能进入​​ .rodata)


.bss 带有运行时初始化程序对于大部分为零或填充相同值的大数组有意义(memset/rep stosd),但在实践中编写 char buf[1024000] = {1}; 会将 1MB 的几乎所有零放入 .data,使用当前的编译器。

否则它不会更有效率mov dword [myvar], imm32 指令至少有 8 个字节长,与在 .data 中静态初始化相比,它在可执行文件中的字节数大约是其两倍。此外,必须执行初始化程序。


相比之下,section .rodata(或 Windows 上的 .rdata)是编译器放置字符串文字、FP 常量和 static const int x = 123 的地方;(实际上,x 通常会在编译单元中使用它的任何地方内联为立即数,让编译器优化掉任何静态存储。但是如果你获取它的地址并传递 &x 到一个函数,编译器需要它存在于内存中的某个地方,那将在 .rodata)


脚注 1:在一个函数内部,int x; 将在堆栈上,如果编译器没有将它优化掉或进入寄存器,当为具有像 x86 这样的堆栈的普通寄存器机编译时.


I could ask this question in the context of C programming as well

在 C 中,优化编译器将处理 int x; x=5; 与函数内部的 int x=5; 几乎相同。不涉及静态存储。查看实际的编译器输出通常很有启发性:参见 How to remove "noise" from GCC/clang assembly output? .

函数之外,在全局范围内,您不能编写类似x=5; 的内容。您可以在 main 的顶部执行此操作,然后您将欺骗编译器生成更糟糕的代码。

在带有static int x = 5; 的函数中,初始化只发生一次。 (在编译时)。如果你做了 static int x; x=5; 每次进入函数都会重新初始化静态存储类,除非你有其他原因需要静态存储类,否则你最好不要使用static。 (例如,返回一个指向 x 的指针,该指针在函数返回后仍然有效。)

关于c - 为什么使用 .data 而不是在 .bss 中保留空间并在运行时初始化,用于 assembly/C 中的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54761947/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com