我很长一段时间试图了解如何在OS下处理程序内存(我使用Windows,但我想这在Linux上会是相同或非常接近).
到目前为止,我知道(主要是感谢stackoverflow用户)局部变量存储在堆栈中.现在我终于明白了为什么.那没关系.
但我仍然想念的是,如何存储和处理全局变量.我想在汇编的基础上知道它.我知道如何处理这些问题,但我无法确定,因为有许多事情我还不知道,这可能使我的想法无法实现.
所以,我的想法是,全局变量位于程序代码的末尾.在最后一条指令之后.为什么我认为它可能是这样的?比起来,你不需要浪费任何额外的内存和CPU时间.因为执行时操作系统将变量及其默认值复制到RAM中.
为什么我认为这是可能的?如果我没有错,那么在现代x86操作系统上,每个程序从0开始都有自己的地址空间.这样,编译非常容易知道全局变量的地址.因为它知道程序的长度,所以它可以计算它在地址空间中的位置.
为什么我认为这可能都错了?Becouse我已经想到为什么在堆栈上创建局部变量的方式相同.当你有一些ELF格式的例程时,你有预编译的例程,只有未解决的变量地址.
另外,在一些文章中,我读到使用malloc分配内存扩展堆.因为我把堆作为程序代码之后的空格,会有错误因为它会成长为堆栈.否则堆栈将需要位于进程地址空间的末尾,但是taht将是可怕的内存浪费.
我试图尽可能多地描述我的观点,所以我希望你能理解我犯了哪些错误,并帮助我填补我所缺少的知识.谢谢.
程序的内存使用量不是编写该程序的语言的函数.您可以编写在C#中使用大量内存的代码,您可以在C中执行相同的操作.
也就是说,我会尝试解决你所问的一些问题:
如何存储和处理全局变量
它们被赋予内存地址.使用全局时,编译器只使用该已知地址.(你有什么期望一个复杂的答案?)
全局变量位于程序代码的末尾
在一些可能是这种情况的架构上,但它不一定是这样.在Windows上(使用可移植可执行文件格式),它们不以任何方式相关,并且可以映射到完全不同的任意位置.实际上,很可能在最近的架构中不会出现这种情况,因为它不鼓励将代码置于数据存在的位置(出于安全考虑 - 您不希望允许缓冲区溢出来覆盖程序代码)
如果我没有错,在现代x86操作系统上,每个程序从0开始都有自己的地址空间
理论上你没有错,但事实上你错了.即使连接器真的可以做到这一点,很少会,因为0被用作null常量.但是,通常问题是,在实际加载代码之前,有动态库或其他消耗过程地址空间的项目.(例如,对代码所在文件的引用,或包含传递给程序的命令行的内存块)
我读到使用malloc分配内存扩展堆
好吧,你假设只有一个堆.至少在Windows上,每个DLL通常都有自己的堆,你可以随意/随意创建堆.在计算机科学课程中经典解释堆的方式通常是假设没有基本操作系统或虚拟内存的系统.
对于现代处理器,您在此处将内存与地址空间混淆.事物的地址位置通常与它们物理存储的位置几乎没有关系.关于虚拟内存的维基百科文章可能会让事情对你更有意义.祝好运!
编辑:
PE exe文件实际上有关于可以与其他数据区分的全局变量的信息
不完全是.PE文件格式具有存储静态数据的部分,并且该文件的区域是存储器映射的.代码知道你正在寻找的特定全局变量的大块中的哪个位置.
Os实际上将它们映射到可以说"最佳"空间
现代处理器使用平面存储器模型.访问任何一个地址就像访问任何其他地址一样容易.
我一直以为OS在运行时不会进一步改变编译代码
它不是(嗯,在大多数情况下,它可能改变的原因是它本身就是一整套蠕虫).要访问全局,代码本身需要知道加载它的基址.在大多数情况下,它可以计算PE文件的数据块的加载位置.也就是说,编译器可以自由地将全局变量放在任何地方; 事实上PE规范有初始化数据的位置并不意味着编译器必须使用它(例如,MingGW,我相信不使用该区域).
首先,.exe是否包含有关所需堆栈大小的信息?
是的,有一些设置既可以控制堆栈的保留大小,也可以控制堆栈的已提交大小.因为Stack Overflows可以在Windows上安全地处理,所以堆栈通常只有1 MB; 在*nix机器上它通常是8MB或更多.
堆栈大小有限吗?
不是我所知道的.那说; 当然有实际的限制.首先,为堆栈保留的地址空间不能用于堆栈以外的任何其他地方.地核空间也有很大一部分由内核保留用于各种用途; 更不用说程序运行的实际代码和数据了.如果您使用的堆栈超过1MB,则应考虑为数据使用堆分配堆栈,并切换到迭代解决方案,或者认真重新考虑程序的运行方式.1MB的堆栈比通常使用的多得多.
第二,你现在有没有关于这个信息的文章,和/或信息PE格式包含的是什么,这个编码在反汇编.exe文件时是如何被看到的
您可以阅读PE规范:http://www.microsoft.com/whdc/system/platform/firmware/pecoff.mspx
在现代系统中,您基本上忘记了确切地知道代码段和数据在物理上和虚拟上的位置.处理器不关心或执行这样的任何事情,因此没有理由任何操作系统或程序被迫使用任何类型的内存组织.特别是,Windows中的Heap概念与计算机科学课程中通常教授的概念大不相同.在Windows(和其他现代操作系统)中,堆只不过是操作系统提供的一堆内存.但是,该存储器的位置是完全可变的.要求一个块的OS,你可以在0x00005556获得它,你可能会得到0xFFFF890的下一个块.没有理由进行区分,因为下面的处理器根本不关心.