【问题标题】:How are stacks in windows x86 stack defined?windows x86堆栈中的堆栈是如何定义的?
【发布时间】:2013-01-30 14:10:50
【问题描述】:

首先,我将展示对堆栈的了解不足,然后我将提出一个无法很好回答的略微连贯的问题,因为该问题不够具体,无法引出一个有条理的问题回答。

那么,当程序运行时,函数被压入堆栈——这意味着堆栈指针是递增还是递减?

堆栈内存分配中究竟存储了什么?指向变量数据的指针,指向程序 est 的指针?我只是不明白堆栈中到底存储了什么(什么数据类型,什么类型的引用,它们是如何存储的)我希望一个函数存储它的局部变量指针和一个指向调用它的地址的指针,以便它可以返回.

此外,windows x86 虚拟内存分配实际上将单个虚拟内存块映射到任意多个物理内存地址,因此堆栈在 windows x86 系统的物理内存中是连续的还是不连续的?

最后,假设堆栈存储在 x86 上的 32 位窗口上的应用程序的用户分配的虚拟内存中,堆栈指针(引用高或低内存地址?)是 31 位(31 因为用户分配和高 2GB 保留给内核分配)小端引用,对吧?

当数据到达堆栈时(例如进入一个函数并为新的 DWORD 分配内存)存储在该 DWORD 中的数据被推入堆栈并且堆栈指针是递增还是递减?系统如何同时感知堆栈的两端?

----这里的ESP?

|-变量x的引用地址

|-函数1中变量x的内存地址要存储的整数数据

|----上面的函数1块^^

|

|

---- OR ESP HERE?

并且从这里引用地址和整数数据将被弹出到寄存器中,并且一个 mov 操作会将整数数据存储在分配的内存位置?

当新数据进入堆栈时,我听说堆栈“向下”增长,但这似乎不合理,因为只有更高和更低的内存地址 - 我知道只有堆栈的一端需要递增/递减,但它是高地址还是低地址,堆栈长度(高度)如何分隔?当堆栈“增长”过大时,系统如何理解?

抱歉所有问题,但我读了很多书,用于描述我一直在读的概念的术语在我的词汇表中没有很好地操作。此外,我在 google、wikipedia 和这个网站上进行了一些检查,但找不到解决我特定问题的解释。

谢谢。

【问题讨论】:

  • 你读完了Wikipedia article吗?它有一个相当彻底的治疗。您的大多数问题都归结为实施细节;堆栈是一种抽象,一种数据结构,您可以有效地使用它而无需考虑其内部实现。
  • 搜索“[assembly] stack”、“[x86] stack”或类似的。例如:stackoverflow.com/questions/13173162/…

标签: windows memory-management assembly operating-system stack


【解决方案1】:

好的。堆栈只是一种抽象数据类型。好的。一个内存数组,您可以将数据放置(puhs)到末尾并移除(pop)它。向上或向下增长,从前面或后面,或任何取决于它的实现方式。很好。

现在 (a) 系统堆栈更加明确。它是由程序分配的 RAM 区域,或本地线程存储或其他任何东西。指针被放置在其内存位置的“末端”,并且向顶部生长。推送将数据放在当前位置的堆栈上(减去数据大小,以便它不会超过末尾),因此在写入之前递减。强制时,新的堆栈指​​针指向最后一个“推送”值的开始。

为什么要倒退?约定和易用性。考虑一个嵌入式系统或一些具有更多有限 RAM 资源的旧系统。如果我们让堆从 RAM 的顶部开始——就在代码和静态/常量数据之后,并且我们需要在同一个 RAM 空间中使用另一种类型的存储,为什么不让它从后面增长呢?这样您就不必担心每个部分必须有多大。当所有 RAM 都用完后,它们将在中间某个地方相遇(并且下一次写入将通过堆栈溢出而繁荣。)易于维护和创建且高效 - 无需猜测适当的大小等。

从这里开始。在这一点上,虚拟地址等不应该让你太担心。当空间不足时,它们只是帮助“繁荣”部分。我怀疑堆栈是否会被分成多个页面,但如果是,让操作系统处理它,一切都很好(而且速度很慢,但那是另一回事了。)

现在堆栈上发生了什么 - 无论您想要什么。通常,传递给函数的参数超出了可以放入寄存器的范围,函数之外不需要的作用域变量,有时用于 this 指针的 c++ 粘合,有时在使用 alloca() 将堆栈视为动态内存时更多 - 你'会经常在线程代码中看到这一点,以帮助防止内存写入竞争条件等。此外,不适合寄存器的值返回的值通常也会返回到堆栈中。基本上,您在函数中看到的每个本地变量都有很大的机会在某个时候存在于堆栈中,因为寄存器已填满并且需要更多空间。因此,许多系统试图确保堆栈内存尽可能快。

要回答您剩下的问题 - 系统可能知道也可能不知道堆栈的两侧 - 取决于平台。我猜windows是通过跟踪如果写入超出结束位置来了解堆栈开始的。不成对的推送/弹出会破坏程序的一天,有时还会导致操作系统挂起(现在更少了)。我无法回答您的 Windows 特定 32/31 位地址问题,因为我在那里没有直接经验。其他人可以抓住那部分。最后,堆栈增长方向是令人困惑的术语。我通常认为系统堆栈是“向上”增长的,但这可能只是我自己。

希望这对您有所帮助并解决一些问题!

【讨论】:

  • 感谢这确实有助于填补我在理解方面的空白 - 我知道我错过了一些信息,但我真的不知道该怎么问。感谢您解释这种不确定性并帮助我理解这一点。
【解决方案2】:

当程序运行时,函数被压入堆栈——这意味着堆栈指针是递增还是递减?

这取决于堆栈的实现方式。如果它从内存的末尾向后增长,它就会递减。如果它从内存的开头向前增长,则递增。

堆栈内存分配中究竟存储了什么?

任何给定的程序或编程语言压入堆栈。这可以包括返回地址、值类型、指向对象的指针和堆栈帧。

windows x86 虚拟内存分配实际上将单个虚拟内存块映射到任意多个物理内存地址,因此堆栈在 windows x86 系统的物理内存中是连续的还是不连续的?

请看这里:http://www.dirac.org/linux/gdb/02a-Memory_Layout_And_The_Stack.php

当堆栈“增长”过大时,系统如何理解?

它到达堆的顶部。

【讨论】:

  • 那个链接真的,真的很有帮助。感谢您帮助我理解这一点!
猜你喜欢
  • 2017-01-04
  • 2011-05-04
  • 1970-01-01
  • 2014-03-11
  • 2014-07-21
  • 1970-01-01
  • 2015-11-16
  • 2012-06-03
  • 2014-06-23
相关资源
最近更新 更多