C++ C语言中的函数序言和结语

C++ C语言中的函数序言和结语,c++,c,assembly,stack-frame,epilogue,C++,C,Assembly,Stack Frame,Epilogue,我知道嵌套函数调用中的数据会进入堆栈。当函数被调用或返回时,堆栈本身实现了一个逐步存储和从堆栈中检索数据的方法。这些方法的名称被称为序言和尾声 我试图搜索有关这个主题的资料,但没有成功。你们知道关于C语言中函数序言和尾声的工作原理的任何资源(网站、视频、文章)吗?或者如果你能解释的话会更好 附言:我只是想了解一些一般情况,不要太详细。有很多资料可以解释这一点: (维基百科) (维基百科) (MSDN) 举几个例子 基本上,正如您所描述的,“堆栈”在程序的执行中有几个用途: 在调用函数时跟踪返

我知道嵌套函数调用中的数据会进入堆栈。当函数被调用或返回时,堆栈本身实现了一个逐步存储和从堆栈中检索数据的方法。这些方法的名称被称为序言和尾声

我试图搜索有关这个主题的资料,但没有成功。你们知道关于C语言中函数序言和尾声的工作原理的任何资源(网站、视频、文章)吗?或者如果你能解释的话会更好


附言:我只是想了解一些一般情况,不要太详细。

有很多资料可以解释这一点:

  • (维基百科)
  • (维基百科)
  • (MSDN)
举几个例子

基本上,正如您所描述的,“堆栈”在程序的执行中有几个用途:

  • 在调用函数时跟踪返回的位置
  • 在函数调用上下文中存储局部变量
  • 将参数从调用函数传递给被调用方
  • 开场白是函数开始时发生的事情。它的职责是设置被调用函数的堆栈框架。epilog正好相反:它是函数中最后发生的事情,其目的是恢复调用(父)函数的堆栈帧

    在IA-32(x86)cdecl中,语言使用
    ebp
    寄存器跟踪函数的堆栈帧。处理器使用
    esp
    寄存器指向堆栈上最近添加的内容(最高值)。(在优化的代码中,使用
    ebp
    作为帧指针是可选的;也可以使用其他方式展开异常堆栈,因此不需要花费指令来设置它。)

    call
    指令做两件事:首先将返回地址推送到堆栈上,然后跳转到被调用的函数。在
    调用之后,
    esp
    立即指向堆栈上的返回地址。(因此,在函数输入时,设置了一个
    ret
    可以执行,将返回地址弹出到EIP中。开场白将ESP指向其他地方,这也是我们需要结束语的部分原因。)

    然后执行序言:

    push-ebp;保存堆栈帧基指针(调用函数的)。
    mov-ebp,esp;将堆栈帧基指针设置为当前值
    ; 堆栈上的位置。
    亚esp,N;将堆栈增加N个字节,以便为局部变量保留空间
    
    在这一点上,我们有:

    。。。
    ebp+4:返回地址
    ebp+0:调用函数的旧ebp值
    ebp-4:(局部变量)
    ...
    
    结语:

    mov-esp,ebp;将堆栈指针放回执行此函数时的位置
    ; 有人打电话来。
    pop-ebp;还原调用函数的堆栈帧。
    ret;返回到调用函数。
    
  • 很好地解释了调用堆栈的概念

  • 简要说明汇编代码以及如何和为什么


  • 每个函数都有相同的序言(函数代码的开始)和尾声(函数的结束)

    序言:序言的结构如下所示: 推ebp 电除尘器

    结语:序言的结构如下: 离开 ret


    更详细地说:

    我参加聚会已经很晚了&我相信在这个问题被问到的过去7年里,你会对事情有一个更清晰的理解,当然,如果你选择进一步追问这个问题的话。然而,我想我还是会尝试一下,尤其是序言和尾声中的“为什么”部分

    此外,公认的答案优雅而简单地解释了尾声和序言的用法,并提供了很好的参考。我只想用为什么(至少是逻辑上的为什么)部分来补充这个答案

    我将引用以下已被接受的答案,并尝试扩展其解释

    在IA-32(x86)cdecl中,语言使用ebp寄存器来保持 跟踪函数的堆栈帧。esp寄存器由 processor指向上最近添加的值(最大值) 堆叠

    call指令做两件事:首先它推送返回 地址,然后跳转到被调用的函数。 通话结束后,esp立即指向 堆叠

    上面引用的最后一行在调用后立即显示
    ,esp指向堆栈上的返回地址。

    为什么? 因此,让我们假设当前正在执行的代码有以下情况,如下图所示(绘制得非常糟糕)

    所以我们要执行的下一条指令是,比如地址2。这就是EIP指向的地方。当前指令有一个函数调用(它将在内部转换为汇编
    call
    指令)

    现在理想情况下,因为EIP指向下一条指令,所以这确实是下一条要执行的指令。但是,由于存在某种偏离当前执行流路径的情况(由于
    调用
    ,这是现在的预期),EIP的值将发生变化。为什么?因为现在可能需要执行另一条指令,可能在其他地方,比如在地址1234(或其他什么地方)。但是,为了按照程序员的意图完成程序的执行流,在转移活动完成后,控件必须返回地址2,因为如果没有发生转移,那么接下来应该执行地址2。让我们在正在进行的
    调用
    的上下文中将此地址2称为
    返回地址

    问题1

    所以,在转移注意力之前