我的内存堆栈混乱,即推送和弹出指令

时间:2010-10-01 19:44:47

标签: assembly

我对内存堆栈有点困惑。

据我所知,为更高地址内存中的进程/线程创建了堆栈,并继续降低地址。现在问题的一部分。当你在堆栈上推送东西时,它首先减少地址,然后在堆栈上存储一些东西。是不是有一些内存丢失,因为Push指令首先减少堆栈指针的地址?我认为首先存储然后减少Sp更合乎逻辑,我在哪里错了?

感谢您的帮助

3 个答案:

答案 0 :(得分:3)

关于是先减少然后先存储或存储然后再减少,有不同的约定。在任何情况下,它都没关系,堆栈指针只是用适当的值初始化(即:它指向上面第一个元素将被存储的地址,或者指向第一个元素将获得的地址存储的)。

答案 1 :(得分:2)

比您可能想知道的更详细。

堆栈可以“降序”(向下生长)或“升序”(成长)。堆栈也可以是“完整”(SP指向“完整”,即堆栈中使用的条目)或“空”(SP指向“空”,即堆栈中未使用的条目。)

大多数筹码都是“完全下降”。我想有一些是“空虚的提升”。另外两个(FA,ED)没有多大用处,只是因为它不清楚如果你可以推送/弹出不同大小的值,它们应该指向哪个字节。

编辑:上面的命名可能有点特定于ARM,只是因为大多数平台都不允许您选择方向。

相关ARM指令的规范助记符实际上是LDMIA(后加载多次递增)和STMDB(之前存储多次递减),用于“完全降序”堆栈,但ARM决定添加LDMFD / STMFD别名,因此程序员只需要记住正在使用的堆栈类型。之前/之后的递增/递减是规范名称,因为ARM体系结构(大部分)是正交的;按照惯例(即EABI)使用堆栈而不是架构本身所持有的东西。例外是r14(LR),r15(PC),以及在不同管理员模式之间被遮蔽的寄存器集。

如果你使用ldm / stm来实现像memcpy()这样的东西,那么命名后的“增量”可能更明智。

(我忽略了Thumb,它有明确的推/弹指令)。

答案 2 :(得分:1)

通常,堆栈指针指向未使用的堆栈空间与堆栈顶部的项目之间的边界。在堆栈向上增长的架构上(地址向下增长),这会使堆栈指针直接指向顶部项目。由于它可以被视为指向顶部项目,因此必须首先更改指针,然后存储。同样在弹出期间,首先加载项目,然后更改指针。

通过插图会更清楚:

//initially
|    |    [CCCC|BBBB|AAAA]
          ^
         esp

//push
|    [    |CCCC|BBBB|AAAA] //decrement
     ^

|    [DDDD|CCCC|BBBB|AAAA] //store
     ^

//pop
|    [DDDD|CCCC|BBBB|AAAA] //load
     ^

|    |DDDD[CCCC|BBBB|AAAA] //increment
          ^