我对内存堆栈有点困惑。
据我所知,为更高地址内存中的进程/线程创建了堆栈,并继续降低地址。现在问题的一部分。当你在堆栈上推送东西时,它首先减少地址,然后在堆栈上存储一些东西。是不是有一些内存丢失,因为Push指令首先减少堆栈指针的地址?我认为首先存储然后减少Sp更合乎逻辑,我在哪里错了?
感谢您的帮助
答案 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
^