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

2022-01-17 00:00:00 c stack compiler-construction c++

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

I am new to C/C++ and assembly lang as well. This could also be very basic question. I am trying to understand how stack frames are built and which variables(params) are pushed to stack in what order?. Some search results showed that....compiler of C/C++ decides based on operations performed within a function. for e.g if the function was suppose to just increment value by 1 of the passed int param and return (similar to ++ operator) it would put all ..the param of the function and local variable within the function in registers and perform addition ....wondering which register is used for returned/pass by value ?....how are references returned? .....difference b/w eax, ebx,ecx and edx.

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

Requesting for a book/blog/link or any kind of material to understand registers,stack and heap references are used/built and destroyed during function call's....and also how main function is stored? Thanks In Advance

推荐答案

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

Your question is borderline here. programmers could be a better place.

理解堆栈等概念的好书可能是 Queinnec 的 Lisp In Small Pieces(它很好地解释了 Lisp 的堆栈是什么).另外,SICP是一本值得阅读的好书.

A good book to understand the concepts of stack etc might be Queinnec's Lisp In Small Pieces (it explains quite well what a stack is for Lisp). Also, SICP is a good book to read.

D.Knuth 的书籍和 MMIX 也是一本不错的读物.

D.Knuth's books and MMIX is also a good read.

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

Read carefully Wikipedia Call stack page.

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

In theory, no call stack is needed, and some languages and implementations (e.g. old SML/NJ) did not use any stack (but allocated the call frame in the garbage collected heap). See A.Appel's old paper Garbage Collection Can be Faster than Stack Allocation (and learn more about garbage collection in general).

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

Usually C and C++ implementations have a stack (and often use the hardware stack). Some C local variables might not have any stack location (because they have been optimized, or are kept in a register). Sometimes, the stack location of a C local variable may change (the compiler would use one call stack slot for some occurrences, and another call stack slot for other occurrences of the same local variable). And of course some temporary values may be compiled like your local variables (so stay in a register, on in one stack slot then another one, etc....). When optimizing the compiler could do weird tricks with variables.

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

On some old machines IBM/360 or IBM z/series, there is no hardware stack; the stack used by the C compiler is a software convention (e.g. some register is dedicated to that usage, without specific hardware support)

想想递归定义的函数的执行(或解释)(就像古老的 factorial 天真编码).阅读recursion(一般来说,计算机科学), 原始递归函数, lambda 演算, 指称语义, 堆栈自动机, 注册分配, 尾调用, 继续, ABI, 中断, Posix 信号, sigaltstack(2), getcontext(2), longjmp(3)等....等...

Think about the execution (or interpretation) of a recursively defined function (like the good old factorial naively coded). Read about recursion (in general, in computer science), primitive recursive functions, lambda calculus, denotational semantics, stack automaton, register allocation, tail calls, continuations, ABI, interrupts, Posix signals, sigaltstack(2), getcontext(2), longjmp(3)etc.... etc...

阅读有关计算机架构的书籍.在实践中,调用堆栈非常重要,以至于几个硬件资源(包括 堆栈指针 寄存器,通常是调用帧 基指针 寄存器,可能还有隐藏的机器,例如缓存相关)专用于通用处理器上.

Read also books about Computer Architecture. In practice, the call stack is so important that several hardware resources (including the stack pointer register, often the call frame base pointer register, and perhaps hidden machinery e.g. cache related) are dedicated to it on common processors.

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

You could also look at the intermediate representations used by the GCC compiler. Then use -fdump-tree-all or the GCC MELT probe. If looking at the generated assembly be sure to pass -S -fverbose-asm to your gcc command.

另请参阅linux 组装方法.

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

相关文章