在C / C ++中理解函数调用的堆栈框架?

我是C / C ++和汇编语言的新手。 这也可能是一个非常基本的问题。 我试图理解堆栈帧是如何构建的以及哪些变量(params)按什么顺序被推送到堆栈? 一些搜索结果显示…. C / C ++的编译器基于函数内执行的操作来决定。 例如,如果函数假设只是将传递的int参数的值递增1并返回(类似于++运算符),它会将函数和局部变量的所有函数和局部变量放在寄存器中并执行加法。 …想知道哪个寄存器用于返回/传递值?….如何返回引用? …..差异b / w eax,ebx,ecx和edx。

在函数调用期间使用/构建和销毁请求书籍/博客/链接或任何类型的材料来理解寄存器,堆栈和堆引用……以及如何存储主函数? 提前致谢

你的问题在这里是临界的。 程序员可能是一个更好的地方。

理解堆栈等概念的好书可能是Queinnec的Lisp In Small Pieces (它很好地解释了Lisp的堆栈)。 此外, SICP是一本很好读的书。

D.Knuth的书和MMIX也很好读。

仔细阅读维基百科调用堆栈页面。

理论上,不需要调用堆栈,并且一些语言和实现(例如旧的SML / NJ)不使用任何堆栈(但是在垃圾收集堆中分配了调用帧)。 请参阅A.Appel的旧纸垃圾收集可以比堆栈分配更快 (并了解有关垃圾收集的更多信息)。

通常C和C ++实现具有堆栈(并且经常使用硬件堆栈)。 某些C局部变量可能没有任何堆栈位置(因为它们已经过优化,或者保存在寄存器中)。 有时,C局部变量的堆栈位置可能会发生变化(编译器会在某些情况下使用一个调用堆栈槽,而对于同一局部变量的其他实例则使用另一个调用堆栈槽)。 当然,一些临时值可能会像您的局部变量一样编译(因此保留在寄存器中,在一个堆栈槽中,然后在另一个堆栈槽中,等等….)。 优化编译器时可以使用变量做奇怪的技巧。

在一些旧机器IBM / 360或I BM z / series上 ,没有硬件堆栈; C编译器使用的堆栈是软件约定(例如,某些寄存器专用于该用途,没有特定的硬件支持)

考虑递归定义函数的执行(或解释)(如天真编码的好旧因子 )。 阅读有关递归 (通常在计算机科学中 ), 原始递归函数 , lambda演算 , 指称语义 , 堆栈自动机 , 寄存器分配 , 尾调用 , 继续 , ABI , 中断 , Posix信号 , sigaltstack(2) , getcontext(2) , longjmp(3)等……等等……

阅读有关计算机体系结构的书籍 实际上,调用堆栈非常重要,以至于几个硬件资源(包括堆栈指针寄存器,通常是调用帧基指针寄存器,以及可能隐藏的机制,例如缓存相关)专用于公共处理器。

您还可以查看GCC编译器使用的中间表示。 然后使用-fdump-tree-all或GCC MELT探针 。 如果查看生成的程序集,请确保将-S -fverbose-asm传递给gcc命令。

另请参见linux程序集howto 。

我给了很多链接。 很难回答得更好,因为我不知道你的背景。

我试图了解如何构建堆栈帧以及哪些变量(params)按什么顺序被推送到堆栈?

这取决于处理器的架构。 但是,通常,堆栈从高地址向低地址增长(如果我们将内存地址视为数值)。 一个堆栈框架“无论此函数放在堆栈上”

放在堆栈上的“东西”通常是:

  • 返回地址返回调用函数。
  • 一个帧指针,指向调用开始时的堆栈帧。
  • 保存的寄存器需要在此函数返回时“保留”。
  • 局部变量。
  • 调用堆栈中“next”函数的参数。

C / C ++编译器根据函数内执行的操作决定。 例如,如果函数假设只是将传递的int参数的值递增1并返回(类似于++运算符),它将把函数和局部变量的所有函数的param放在寄存器中的函数中并执行加法….想知道哪个寄存器用于返回/传递值?….如何返回引用?

编译器具有如何传递参数的规则,对于常规函数调用[即,不是“内联”函数],参数总是以相同的顺序传递,在寄存器和堆栈存储器的相同组合中。 如果不是这种情况,编译器必须在决定传递参数之前确切地知道函数的作用。

不同的处理器架构有不同的规则。 x86-32通常有一个或两个用于输入参数的寄存器,通常有一个寄存器用于返回值。 x86-64最多使用5个寄存器将前五个值传递给函数。 任何其他参数都在寄存器中传递。

返回引用与返回任何其他值没有什么不同。 值(在这种情况下是要返回的对象的地址)。 在x86-32中,返回值在EAX中。 在x86-64中,返回值在RAX中。 在ARM中,R0用于返回值。 在29K中,R96用于返回值。