程序集如何访问/存储堆栈上的变量

时间:2014-02-28 09:42:51

标签: c assembly stack

在汇编中您可以将数据存储在寄存器或堆栈中。在任何给定时刻只能访问堆栈的顶部(对吗?)。请考虑以下C代码:

main(){
    int x=2;
    func();
}

func( int x ){
    int i;
    char a;
}

在调用func()时,以下内容被推入堆栈(考虑使用32位系统):

variable x (4 bytes, pushed by main)
<RETURN ADDRESS> (4 bytes pushed by main?)
<BASE POINTER> (4 bytes pushed by func())
variable i (4 bytes, pushed by func())
variable a (1 byte, pushed by func())

我有以下问题:

  1. 在C代码中,您可以从函数内部的任何位置访问本地变量,但在汇编中,您只能访问堆栈的顶部。 C代码被转换为程序集(在机器代码中,但程序集是它的可读形式)。那么程序集如何支持读取不在堆栈顶部的变量?

  2. 在我的例子中,我是否遗漏了任何可能被推入堆栈的内容?

  3. 在汇编中,如果你在堆栈或int上推送一个char,它怎么能确定它需要推送4个字节还是1个字节?因为它使用相同的操作(推)对吗?

  4. 提前致谢 克。 Maricruzz

4 个答案:

答案 0 :(得分:3)

将函数开头的堆栈指针放入寄存器,然后通过此基址加上变量的偏移量来访问变量/参数。

如果要查看代码,而不是创建目标文件,请让编译器停止创建汇编程序文件。然后你就可以看到它是如何工作的。 (当然,这需要你有一个有效的C程序,不像你现在在问题中那样。)

答案 1 :(得分:2)

编译器正在生成程序集,每个指令集可能不同,但在一天结束时,堆栈只是一个寄存器,其中包含一个存储器地址。编译器正在创建并知道它正在创建的函数的整个范围,并知道在堆栈中查找本地数据项的每个数据项的距离,因此它将根据该指令集创建适当的代码以访问本地数据项。项目

您需要制作堆栈指针的副本和/或使用堆栈指针作为操作数进行数学运算的一些指令集,但是作为该数学运算的一些其他寄存器,然后基于该数学运算(堆栈指针+ 8个字)例如,您访问该内存地址。某些指令集具有寻址模式,您可以在加载或存储中将偏移量应用于堆栈指针,数学运算是指令执行的一部分,您不必使用中间结果和寄存器。

答案 2 :(得分:1)

  

在任何给定时刻只能访问堆栈顶部(对吗?)

不,通常ISA也有访问堆栈上其他元素的指令。也就是说,访问堆栈中的元素不仅限于pushpop之类的操作;通常,你可以在堆栈位置和寄存器之间来回mov

答案 3 :(得分:1)

Assembly可以按地址访问任何内存(就像C)。

简单的,未优化的程序会在方法执行之前将所有局部变量放在堆栈上,因此变量地址是执行帧的地址加上一些移位。

然后程序可以简单地使用poppush方法在堆栈顶部存储其他变量(即某些表达式的子结果)。

要点:

  1. 指向堆栈顶部的寄存器(ESP中的x86
  2. 调用push将变量移动到堆栈顶部并增加此寄存器
  3. 调用pop是从堆栈顶部移动变量并减少此寄存器
  4. 调用mov是在内存和寄存器之间移动变量而不对堆栈寄存器(ESP)执行任何操作。