我只能想象 1)参数; 2)局部变量;
还有什么?
1)功能返回地址? 2)功能名称?
答案 0 :(得分:5)
这实际上取决于平台和架构,但通常是:
据我所知,函数名永远不会出现在堆栈中,除非你的代码放在那里。
答案 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字节边界上对齐。
调用约定是复杂的野兽,堆栈框架布局不适合胆小的人!