gpt4 book ai didi

c - Windows下运行的C二进制文件中的已初始化数据段

转载 作者:行者123 更新时间:2023-12-01 11:58:48 27 4
gpt4 key购买 nike

我很长时间试图了解在OS(我使用Windows,但我想这在Linux上将是相同或非常接近)下如何处理程序存储器。

到目前为止,我知道(主要是感谢您的stackoverflow用户)局部变量存储在堆栈中。现在我也终于明白了为什么。这样就可以了。

但是我仍然想念的是,如何存储和处理全局变量。我想以汇编程序为基础来了解它。我对如何处理这些想法有想法,但是我不能确定,因为我仍然不知道很多事情,这可能会使我的想法无法实现。

因此,我的想法是,全局变量位于程序代码的末尾。最后一条指令之后。为什么我认为可能是这种方式?因为,您将不需要浪费任何额外的内存和CPU时间。因为执行时,变量及其默认值将由OS复制到RAM中。

为什么我认为这有可能?因为,如果我没有记错的话,在现代的x86操作系统上,每个程序都有从0开始的自己的地址空间。这样,编译后就很容易知道全局变量的地址。因为它知道程序的长度,所以它可以计算其在地址空间中的位置。

为什么我认为这可能全错了?因为我已经想过,为什么要在栈中创建局部变量呢?而且当您有一些ELF格式的例程时,您就已经预编译了例程,只是带有未解析的变量地址。

另外,在某些文章中,我读到了使用malloc分配内存可以扩展堆。而且因为我把堆当作程序代码后的空间,所以会出错,因为它会长到堆栈中。否则,堆栈必须位于过程地址空间的末尾,但是这将浪费大量的内存。

我试图尽我所能描述自己的观点,希望您能理解我在哪里犯了一些错误,并帮助我填补我所缺少的知识。谢谢。

最佳答案

程序的内存使用情况与编写该程序的语言无关。您可以在C#中编写使用大量内存的代码,也可以在C中执行相同的操作。

也就是说,我将尝试解决您的一些问题:

如何存储和处理全局变量

它们被赋予了内存地址。使用全局时,编译器仅使用该已知地址。 (什么,您期望得到一个复杂的答案?)

全局变量位于程序代码的末尾

在某些架构上可能是这样,但并非必须如此。在Windows(使用可移植可执行文件格式)上,它们没有任何关联,并且可以映射到完全不同的任意位置。实际上,在最新的体系结构上很可能不是这种情况,因为这种体系不鼓励将代码放置在数据所在的位置(出于安全目的-您不希望允许缓冲区溢出来覆盖程序代码)

如果我没看错的话,在现代x86操作系统上,每个程序都有自己的地址空间,从0开始

您在理论上没有错,但实际上您错了。即使链接器确实可以做到这一点,也很少有人会这么做,仅仅因为0被用作null常量。但是,通常的问题是,存在动态库或占用项目地址空间的其他项目,而这实际上是在代码实际加载之前。 (例如,对代码所在文件的引用,或包含传递给程序的命令行的内存块)

我读到使用malloc分配内存会扩展堆

好吧,您假设只有一个堆。至少在Windows上,每个DLL通常都有自己的堆,您可以随意创建堆。在计算机科学课程中经典地解释堆的方式通常是假设系统没有正在运行的基本操作系统或虚拟内存。

您在这里将现代处理器的内存与地址空间混淆了。事物的地址位置通常与它们的物理存储位置几乎没有关系。 Wikitia上有关Virtual Memory的文章可能会使您觉得更有意义。祝好运!

编辑:

PE exe文件实际上包含有关可以与其他数据区分开的全局变量的信息

不完全是。 PE文件格式有一段存储静态数据的部分,并且该文件的区域是内存映射的。该代码知道该大块中您要查找的特定全局变量在哪里。

Os实际上将它们映射到说“最佳”可用空间

现代处理器使用平面内存模型。访问任何一个地址与访问其他任何地址一样容易。

我一直以为OS在运行时不会进一步更改已编译的代码

它不是(嗯,在大多数情况下,它可能改变的原因是蠕虫本身及其自身的全部危害)。要访问全局代码,代码本身需要知道加载它的基址。大部分情况下,它可以计算出PE文件的数据块的加载位置。也就是说,编译器可以自由地将全局变量放在几乎任何地方。 PE规范中有用于初始化数据的位置这一事实并不意味着编译器必须使用它(例如,MingGW,我相信不使用该区域)。

首先,.exe是否包含有关所需堆栈大小的信息?

是的,有一些设置可以控制堆栈的保留大小和堆栈的提交大小。由于可以在Windows上安全地处理堆栈溢出,因此堆栈通常只有1 MB;在* nix机器上,通常为8MB或更多。

堆栈大小是否受限制?

据我所知。那说;当然有实际的局限性。首先,为堆栈保留的地址空间将不能用于堆栈以外的任何其他空间。内核还保留了很大一部分地址空间,用于各种用途。更不用说程序在其上运行的实际代码和数据了。如果您使用的堆栈超过1MB,则应考虑为数据使用堆分配的堆栈,然后切换到迭代解决方案,或者认真考虑一下程序的运行方式。 1MB的堆栈比通常使用的要多得多。

其次,您现在是否有任何文章包含此信息,和/或PE格式包含的内容是什么,在反汇编.exe文件时如何编码该信息?

您可以阅读PE规范:http://www.microsoft.com/whdc/system/platform/firmware/pecoff.mspx

在现代系统上,您实际上可以忘记确切地知道物理和虚拟代码段和数据的位置。处理器不关心或强制执行此类操作,因此没有理由强迫任何操作系统或程序使用任何类型的内存组织。特别是,Windows中的堆概念与计算机科学课程中通常讲授的概念有很大不同。在Windows(和其他现代OS)中,堆不过是OS分配的一堆内存而已。但是,该内存的位置是完全可变的。要求操作系统提供一个块,您可能会在0x00005556处得到它,而下一个块会得到0xFFFF890。没有区别的理由,因为下面的处理器根本不在乎。

关于c - Windows下运行的C二进制文件中的已初始化数据段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3579594/

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