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

C 程序集如何访问/存储堆栈上的变量,c,assembly,stack,C,Assembly,Stack,在汇编中,您可以将数据存储在寄存器或堆栈中。在任何给定时刻都只能访问堆栈的顶部(对吗?)。考虑下面的C代码: main(){ int x=2; func(); } func( int x ){ int i; char a; } 调用func()时,会将以下内容推送到堆栈上(考虑32位系统): 变量x(4个字节,由main推送) (由main推送的4个字节?) (由func()推送的4个字节) 变量i(4个字节,由func()推送) 变量a(1字节,由func(

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

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

func( int x ){
    int i;
    char a;
}
调用func()时,会将以下内容推送到堆栈上(考虑32位系统):

变量x(4个字节,由main推送)
(由main推送的4个字节?)
(由func()推送的4个字节)
变量i(4个字节,由func()推送)
变量a(1字节,由func()推送)
我有以下问题:

  • 在C代码中,您可以从函数中的任何位置访问局部变量,但在汇编中,您只能访问堆栈的顶部。C代码被翻译成汇编(在机器代码中,汇编是它的可读形式)。那么,程序集如何支持读取不在堆栈顶部的变量呢

  • 在我的示例中,是否遗漏了也会被推到堆栈中的任何内容

  • 在汇编中,如果在堆栈上推送字符或int,它如何确定需要在那里推送4字节还是1字节?因为它使用相同的操作(推送),对吗

  • 提前谢谢 马里克鲁兹

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


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

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


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

    汇编
    可以通过地址访问任何内存(就像
    C

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

    然后,程序可以简单地使用
    pop
    push
    方法在堆栈顶部存储附加变量(即某些表达式的子结果)

    总结:

  • 有一个寄存器(
    ESP
    x86
    中)指向堆栈的顶部
  • 调用
    push
    将变量移动到堆栈顶部并增加该寄存器
  • 调用
    pop
    是从堆栈顶部移动变量并减少该寄存器
  • 调用
    mov
    是在内存和寄存器之间移动变量,对堆栈寄存器不做任何操作(
    ESP

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


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

    谢谢!是否也可以在某个地方看到堆栈的当前内容?任何用于此的工具?@Maricruzz任何合适的调试器都应该具有此功能。按操作数大小递减esp,则将操作数存储在[esp]。pop从[esp]加载操作数,然后按操作数的大小递增esp。禁用“帧指针”后,C生成使用esp偏移量定位变量的代码。启用“帧指针”后,一个函数执行一个推式esp | mov ebp、esp,并根据ebp的大部分偏移量。
    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())