计算机的堆栈和汇编语言

时间:2013-10-26 13:15:11

标签: assembly stack

现在我正在尝试在x86系统上学习汇编语言。因此,我正在准备“从头开始编程”一书。 (可在http://download.savannah.gnu.org/releases/pgubook/免费获得)

在第53页上,解释了计算机堆栈的工作方式:

  

计算机的堆栈位于最顶端   记忆地址。您可以通过一个将值推到堆栈顶部   指令叫做pushl。 [...]好吧,我们说它是顶级的,但堆栈的“顶部”实际上是堆栈内存的底部。 [...]在内存中,堆栈从顶部开始   内存并由于架构考虑而向下增长。因此,   当我们提到“堆栈顶部”时,请记住它位于堆栈的底部   存储器中。

我得到的那部分。假设堆栈的内存从地址0开始,到地址11(包括)结束。这意味着堆栈上当前有三个单词(每个4个字节)。根据我的理解,堆栈“顶部”上的字当前占用地址8,9,10和11.(因为一个字有4个字节,因此占用主存储器中的四个存储位置)。但是,这本书现在说如下:

  

堆栈寄存器%esp始终包含指向堆栈当前顶部的指针。

好的,在我的例子中,%esp寄存器将保存地址8.它指向当前位于堆栈顶部的单词。但...

  

每当我们用pushl将一些东西推到堆栈上时,%esp被减去4,这样它就指向堆栈的新顶部(记住,每个字长四个字节,堆栈向下增长)。

什么?是不是完全相反?如果我将另一个4字节大小的机器字压入堆栈,这个字将占用主存储器地址12到15.就像他们说的:堆栈向下增长。现在%esp寄存器指向当前位于堆栈顶部的单词。它从地址12开始。在我们将另一个单词推入堆栈之前,存储在%esp中的地址为8.因此%esp显然已添加4,而不是减去。他们从哪里得到减法?我错过了什么?我很困惑......

非常感谢帮助;)

3 个答案:

答案 0 :(得分:3)

  

如果我将另一个4字节大小的maschine字推入堆栈,这个字将占用主存储器地址12到15.就像他们说的:堆栈向下增长。

向下意味着朝向较低地址,因此在堆栈上推送另一个值意味着减去4并将值写入新位置。所以%esp变为4。

  +--------+
8 |12345678| <- top of stack before push
  +--------+
4 |11223344| <- top of stack
  +--------+
0 |00000000|
  +--------+

答案 1 :(得分:0)

通常“内存地址的顶部”是指最高地址。例如,您的堆栈可能从0x00105000开始;如果您添加了一个字词,则会将esp移至0x00104ffc(即您在内存地址中向下增长 )。参见例如here获得了一个漂亮的图表。

答案 2 :(得分:0)

如果输入功能并且堆栈位于0x100。通常,堆栈从高地址向低地址向下增长,朝向零。所以,如果你再按下一个4字节项,那么堆栈“top”现在是0xFC。按另一个,0xF8,依此类推。

另一件令人讨厌的事情是ebp vs esp。

通常,处理器有一个堆栈指针,一个特殊的或有时是通用的寄存器,它具有与之相关的特定指令,push,pop,以及堆栈指针相对寻址的加载和存储。此外,对于堆栈帧,编译器使用与堆栈指针不同的通用(或专用)寄存器并不罕见。为什么?使编译器生成的代码的读取和调试更容易一些。

例如,在输入函数时,您可以将堆栈指针的副本复制到另一个寄存器中,并且在寄存器不移动的函数期间,这允许您对该寄存器进行相对寻址以查找局部变量以及函数参数(如果此编译器和处理器倾向于在堆栈上传递参数)。因此,在整个函数中,您可以使用相同的偏移量访问这些局部变量中的任何一个。如果您没有使用堆栈帧,那么,如果出于优化原因(保存堆栈内存)堆栈指针在函数内是动态的,那么从堆栈指针到局部变量和基于堆栈的函数参数的相对偏移也将是动态的并且更难阅读和调试。 (同时保存堆栈空间并返回用于其他用途的寄存器,两种优化方式)。

在任何情况下,当调用嵌套函数时,调用函数的函数需要将堆栈指针放在“堆栈顶部”,以便该函数可以像任何其他函数一样享受堆栈并假设它可以使用/ destroy为了自己的目的,任何超出堆栈结束的东西。