C 程序集如何访问/存储堆栈上的变量
在汇编中,您可以将数据存储在寄存器或堆栈中。在任何给定时刻都只能访问堆栈的顶部(对吗?)。考虑下面的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(
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()推送)
我有以下问题:
不,通常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())