调用函数时堆栈上有什么?

时间:2011-04-08 01:56:38

标签: c++ c compiler-construction programming-languages callstack

我只能想象 1)参数; 2)局部变量;

还有什么?

1)功能返回地址? 2)功能名称?

3 个答案:

答案 0 :(得分:5)

这实际上取决于平台和架构,但通常是:

  • 功能返回地址
  • 调用者CPU寄存器的保存值 - 最重要的是,调用者的堆栈帧指针值
  • 使用alloca()分配的变量。
  • 有时 - 用于异常处理的额外内容,这非常依赖于平台。
  • 有时候 - 用于检测堆栈破坏的保护值

据我所知,函数名永远不会出现在堆栈中,除非你的代码放在那里。

答案 1 :(得分:2)

我认为a picture确实是千言万语。

答案 2 :(得分:2)

这取决于召唤惯例;对于Unix,您通常在SYSV ABI(应用程序二进制接口)中查找此信息。

你可能会发现:

  • 返回地址(如果该机器是一种流行的英特尔架构)。在更现代的体系结构中,返回地址在寄存器中传递。

  • Callee-saving寄存器 - 这些寄存器“属于”被调用者选择借用的调用者,因此必须保存和恢复。

  • 任何无法在寄存器中传递的传入参数。在IA-32中, no 参数在寄存器中传递;他们都进入了堆叠。在x86-64中,最多可以在寄存器中传递六个整数和六个浮点参数,因此很少需要将堆栈用于此目的。

  • 您可能找到或未找到已保存的堆栈指针或帧指针。大多数现代调用约定没有帧指针,以节省额外的寄存器。在这种设计中,每个帧的大小在编译时是已知的,因此恢复旧的堆栈指针只是添加常量的问题。但这使得实施alloca()更加困难。

    旧的英特尔调用约定同时使用堆栈指针和帧指针,它会烧掉额外的寄存器,但它会简化alloca()并堆叠展开。

  • 存储类auto的局部变量在堆栈上分配。

  • 如果硬件没有提供足够的寄存器来保存计算的所有中间结果,那么堆栈可能包含编译器临时值,这些值包含“溢出”的值。 (如果在任何时候,实际中间结果的数量 - 程序中稍后需要的数量 - 超过了编译器可用于存储中间结果的寄存器数量,则会发生这种情况。)

  • 您可以找到使用alloca()分配的变量。

  • 您可能会找到元数据,说明哪些PC范围适用于哪些异常处理程序或其他与平台相关的异常处理。

  • C和C ++不支持垃圾收集,但是在一种语言中,你经常会找到元数据来识别堆栈框架中你会找到指针的位置。

  • 最后,堆栈可能包含“填充”,用于确保堆栈指针在8字节或16字节边界上对齐。

调用约定是复杂的野兽,堆栈框架布局不适合胆小的人!