据我所知,当一个进程分配局部变量时,它会通过将它们作为堆栈推送到内存中来实现,但仍然通过使用堆栈指针的偏移来引用它们作为随机内存来引用它们(来自此线程) What is the idea behind using a stack for local variables?)。
但是,它如何知道哪些变量有什么偏移?我是否以正确的方式思考这个问题?
答案 0 :(得分:5)
局部变量的偏移被"烘焙到"机器码为常量。编译器完成时,程序称为局部变量的东西将被编译器分配的固定内存偏移量替换。
我们假设您声明了三个局部变量:
char a[8];
int b;
short c;
编译器为这些变量分配偏移:a
偏移0
,b
偏移8
,c
偏移12
1}}。我们假设您的代码为b += c
。编译器将其转换为如下所示的代码块:
LOAD @(SP+8)
ADD @(SP+12)
STORE @(SP+8)
此处更改的唯一值是SP
(堆栈指针)。所有偏移都是数字常量。
答案 1 :(得分:2)
前言:以下文本以x86架构为例。其他架构确实以不同的方式处理事情。
[...]它是通过将它们作为堆栈推入内存来实现的,[...]
那很接近。 它是通过将它们推入内存 ON 堆栈[当前进程] 来实现的。每个进程都有自己的堆栈。因此,对于每个上下文切换,此堆栈帧确实会发生变化 - 其局部变量(在堆栈上)也是如此。
通常(!)本地定义的变量相对于保存并存在于EBP
寄存器中的堆栈帧被引用。与全局定义的可变数据相比,这是相对于数据段基础引用的。因此,每个进程都有自己的堆栈和自己的局部变量。
较新的编译器可以使寄存器EBP
无效并引用相对于ESP
寄存器的变量。这有两个后果:
EBP
值作为当前堆栈帧的参考来识别局部变量)。因此,如果没有单独的调试信息文件,这会使调试更加困难。所以回答你的主要问题
流程如何跟踪其局部变量
进程会跟踪 Stack Frame (包含 Local Variables ),但不会跟踪 Local Variables 本身。并且堆栈帧随每个过程开关而变化。 局部变量仅相对于保存在寄存器EBP
中的堆栈帧指针(或相对于堆栈指针 { {1}},这取决于编译器设置。)
答案 2 :(得分:1)
编译器完成记忆偏移的工作。这些偏移只是硬编码。喜欢将变量加载到寄存器(例如,到eax),编译器会产生类似mov eax, [esp-4]
的东西,其中esp是堆栈指针寄存器,4是偏移量。如果新的变量将被推送到下一个mov to get / set变量将具有更大的偏移量。所有这些都是编译时间分析。
此外,某些平台上的堆栈可能会反转 - 因此偏移量将为正。