函数的局部变量是如何从堆栈中访问的

How are the function local variables accessed from the stack?

本文关键字:堆栈 访问 局部变量 函数      更新时间:2023-10-16

来源http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/

以下是当函数调用:

  1. 函数调用之外的指令的地址被推送到堆栈上。这就是CPU在函数返回
  2. 堆栈上为函数的返回类型留出了空间。这只是一个占位符
  3. CPU跳转到函数的代码
  4. 堆栈的当前顶部保存在一个称为堆栈帧的特殊指针中
  5. 在这一点之后添加到堆栈中的所有内容都被认为是函数的"本地"
  6. 所有函数参数都放置在堆栈上
  7. 函数内部的指令开始执行
  8. 局部变量在定义时被推送到堆栈中

我不确定第6点是如何运作的。如果所有函数参数都放在堆栈上,如何访问它们?

例如,如果有三个参数abc,并且从的顶部像这样放置在堆栈上

| a |
| b |
| c |
|   |
 ...
|___|

现在,当函数想要访问c时会发生什么?是否弹出ab

堆栈是隐喻堆栈。请记住它仍然是一个RAM,因此如果您知道要查找什么,您可以访问每个地址,而无需弹出其余地址。

由于自动变量的大小在编译时是已知的-编译器为每个变量标记offset,因此偏移量是从堆栈开始的自动变量部分[或堆栈的头,两者都是有效的,具体实现可能取决于体系结构]确定的,并且它只通过:start + offset为每个变量的偏移量访问它们。

不,它们不是。堆栈指针(通常是esp注册表)指向aesp+8h指向besp+16h指向c等等。不需要弹出a

请注意,这是一个实现细节。你不应该担心这些。我给出的数字纯粹是理论上的,在一些架构中,递减地址被赋予后一个参数,而在另一些架构中则相反。无法保证会发生这种情况。

编辑:在我看来,这不是一个非常可靠的信息来源。它谈到了堆栈和堆,但这些都是实现细节,甚至可能不存在。

标准中也没有任何约束,任何东西都可以通过堆栈来实现。例如,我生成了以下代码:

void foo(int x, int y, int z)
{
01241380  push        ebp  
01241381  mov         ebp,esp 
01241383  sub         esp,0CCh 
01241389  push        ebx  
0124138A  push        esi  
0124138B  push        edi  
0124138C  lea         edi,[ebp-0CCh] 
01241392  mov         ecx,33h 
01241397  mov         eax,0CCCCCCCCh 
0124139C  rep stos    dword ptr es:[edi] 
    int c = x;
0124139E  mov         eax,dword ptr [x] 
012413A1  mov         dword ptr [c],eax 
    c = y;
012413A4  mov         eax,dword ptr [y] 
012413A7  mov         dword ptr [c],eax 
    c = z;
012413AA  mov         eax,dword ptr [z] 
012413AD  mov         dword ptr [c],eax 
}
012413B0  pop         edi  
012413B1  pop         esi  
012413B2  pop         ebx  
012413B3  mov         esp,ebp 
012413B5  pop         ebp  

所以你看,那里没有堆栈。运行时可以直接访问元素:dword ptr [x]等。

它使用堆栈指针和相对地址来指出c.