据我所知,当一个进程分配本地变量时,它会将这些变量作为堆栈推送到内存中,但通过使用与堆栈指针的偏移来引用它们来访问它们(来自此线程 使用堆栈存储本地变量背后的思想是什么?)。
然而,它如何知道哪些变量具有什么偏移量呢?我这样想对吗?
然而,它如何知道哪些变量具有什么偏移量呢?我这样想对吗?
本地变量的偏移量被“嵌入”机器代码中作为常量。编译器完成后,程序中所引用的本地变量将被替换为编译器分配的固定内存偏移量。
例如,您声明了三个本地变量:
char a[8];
int b;
short c;
a
位于偏移量0
,b
位于偏移量8
,c
位于偏移量12
。假设你的代码执行了b += c
。编译器将其转换为一个代码块,看起来像这样:LOAD @(SP+8)
ADD @(SP+12)
STORE @(SP+8)
SP
(栈指针),所有偏移量都是数字常量。int
大小为 4 字节的平台。 - kfxSP
才会发生改变,此时当前函数处于“暂停”状态。一旦其他函数返回,SP
就会恢复到调用之前的值,因此当前函数可以再次以其当前偏移量访问其本地变量。 - Sergey Kalinichenkoi
和j
。然后在第一次使用j
之前使用i
,并停止。之后开始使用j
,再也不使用i
。当i
和j
是两个相邻循环的索引时,这种情况很常见。在这种情况下,编译器允许为i
和j
分配相同的偏移量。 - Sergey Kalinichenkogcc -O3
在 32 位 x86 上的两种方式:https://godbolt.org/g/tbxzNY。 - Peter Cordespush
指令,只有load/store,并且相对于堆栈指针引用本地变量与引用任何其他寄存器没有区别。 - Peter Cordesmov eax, [esp-4]
的代码,其中esp是堆栈指针寄存器,4是偏移量。如果推入新变量,下一个mov的偏移量将会更大。所有这些都是编译时分析。另外,在某些平台上,堆栈可能会反转,因此偏移量将为正数。mov eax,[esp + 4]
。只有System V x86-64 ABI具有红区,在其中您可以在叶函数中安全地将本地变量放置在rsp
以下,即使在安装了信号处理程序的一般情况下也是如此。 (在这种情况下,您将使用[rsp-4]
。尽管gcc在编译x32 ABI(长模式下的32位指针)时会错过优化,其中它甚至会对访问堆栈使用地址大小前缀,因此您实际上可以获得一些gcc版本以正确的选项发出mov eax,[esp-4]
) - Peter Cordes