栈帧是什么_函数栈帧

栈帧是什么_函数栈帧浅析函数调用的栈帧新乐于心温文尔雅的偏执狂​关注他10人赞同了该文章​目录在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等。一切的函数调用都要将不同的数据、地址压入或者弹出栈。什么是栈?栈是一种LIFO(后进先出)可以想象下函数调用的时候

大家好,欢迎来到IT知识分享网。

浅析函数调用的栈帧

浅析函数调用的栈帧

 

目录

在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等。一切的函数调用都要将不同的数据、地址压入或者弹出栈。

什么是栈?

栈是一种LIFO(后进先出)
可以想象下函数调用的时候,父函数调用子函数,父函数在前,子函数在后。返回的时候子函数先返回,父函数后返回。ps:递归就是明显利用函数调用这种栈的结构来实现的。

什么是栈帧?

栈帧本质上是一种栈,只是这种栈专门用于保存函数调用过程中的各种信息(参数,返回地址,本地变量等)。栈帧有栈顶和栈底之分,其中栈顶的地址最低,栈底的地址最高。

两个主要寄存器

1. ESP寄存器
栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

2.EBP寄存器
基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

 

栈帧是什么_函数栈帧

一般来说,我们将 %ebp 到 %esp 之间区域当做栈帧(也有人认为该从函数参数开始,不过这不影响分析)。并不是整个栈空间只有一个栈帧,每调用一个函数,就会生成一个新的栈帧。在函数调用过程中,我们将调用函数的函数称为“调用者(caller)”,将被调用的函数称为“被调用者(callee)”。在这个过程中,1)“调用者”需要知道在哪里获取“被调用者”返回的值;2)“被调用者”需要知道传入的参数在哪里,3)返回的地址在哪里。同时,我们需要保证在“被调用者”返回后,%ebp%esp 等寄存器的值应该和调用前一致。因此,我们需要使用栈来保存这些数据。

函数调用实例

函数的调用

//被调函数 callee int CalleeFunction(int x, int y, int z) { int a, b, c; a = 4; b = 5; c = 6; return; } //主调函数 caller int CallerFunction() { int x = 1, y = 2, z = 3; //调用被调函数  CalleeFunction(1, 2, 3); ... }

我们来看下Callee函数的汇编代码

_CalleeFunction: push %ebp ; //保存%ebp的值  movl %esp, $ebp ; //将%esp的值赋给%ebp,使新的%ebp指向栈顶  movl -12(%esp), %esp ; //分配额外空间给本地变量  movl $4, -4(%ebp) ; movl $5, -8(%ebp) ; movl $6, -12(%ebp) ; 

此时调用者做了两件事情:第一,将被调用函数的参数按照从右到左的顺序压入栈中。第二,将返回地址压入栈中。这两件事都是调用者负责的,因此压入的栈应该属于调用者的栈帧。我们再来看看被调用者,它也做了两件事情:第一,将老的(调用者的) %ebp 压入栈,此时 %esp 指向它。第二,将 %esp 的值赋给 %ebp%ebp 就有了新的值,它也指向存放老 %ebp 的栈空间。这时,它成了是函数 CalleeFunction() 栈帧的栈底。这样,我们就保存了“调用者”函数的 %ebp,并且建立了一个新的栈帧。

栈帧是什么_函数栈帧

在 %ebp 更新后,我们先分配一块0x12字节的空间用于存放本地变量,这步一般都是用 sub 或者 mov 指令实现。在这里使用的是 movl。通过使用 mov 配合 -4(%ebp)-8(%ebp) 和 -12(%ebp) 我们便可以给 ab 和 c 赋值了。

栈帧是什么_函数栈帧

函数返回

和调用函数时正好相反。当函数完成自己的任务后,它会将 %esp 移到 %ebp 处,然后再弹出旧的 %ebp 的值到 %ebp。这样,%ebp 就恢复到了函数调用前的状态。

//被调函数 callee int CalleeFunction(int x, int y, int z) { int a, b, c; ... return; }

汇编代码

_CalleeFunction:
    push %ebp
    movl %esp, %ebp
    movl -12(%esp), %esp
    ...
    mov %ebp, %esp
    pop %ebp
    ret

ret 指令,这个指令相当于 pop + jum。它首先将数据(返回地址)弹出栈并保存到 %eip 中,然后处理器根据这个地址无条件地跳到相应位置获取新的指令。

栈帧是什么_函数栈帧被调用函数返回后的栈帧

小结

这批函数栈帧分析为基础 方便大家理解golang启动过程中对栈帧的一系列操作,比如最骚的把goexit()塞入到newg的栈顶等过程~

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/29927.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信