栈帧

概念

栈帧:也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构,每次函数的调用,都会在调用栈(call stack)上维护一个独立的栈帧(stack frame)

栈帧的内容

  • 函数的返回地址和参数

  • 临时变量:包括函数的非静态局部变量,以及编译器自动生成的其他临时变量

  • 函数调用上下文

  • 两个指针:ebp又称帧指针(frame pointer),指向当前栈帧的底部; esp,又称栈针织(stack pointer),始终指向栈顶

函数调用

函数调用过程中分:函数调用者(caller)和被调用的函数(callee)

调用者需要知道被调用函数的返回值

被调用函数需要知道传入的参数和返回的地址

步骤:

  1. 参数入栈:将参数按照调用约定依次压入系统栈

  2. 返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈,供函数返回时继续执行,也就是保护现场和恢复现场

  3. 代码跳转:处理器将代码区跳转到被调用函数的入口处

  4. 栈帧调整:

  5. 将调用者的ebp压入栈,保存指向栈底ebp地址(用于恢复现场),此时esp指向新的栈顶位置

  6. 将当前栈帧切换到新栈帧(将esp值装入ebp,跟新栈底),此时ebp指向栈顶,

  7. 给新栈帧分配空间

函数返回

步骤:

  1. 保存被调用函数的返回值到eax寄存器

  2. 恢复esp同时收回局部变量空间

  3. 将上一个栈帧底部位置恢复到ebp

  4. 弹出当前元素栈顶元素,从栈中取到返回地址,并跳转到该位置,也就是再回到调用者,执行后续代码

举例说明

c代码:

int sum(int x,int y){
int z=x+y;
return z;
}
int main(){
int a=1;
int b=3;
int c=sum(a,b);
}

汇编,且关闭编译器优化-O0

    .file    "test.c"
.text
.globl sum
.def sum; .scl 2; .type 32; .endef
.seh_proc sum
sum:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $16, %rsp
.seh_stackalloc 16
.seh_endprologue
movl %ecx, 16(%rbp)
movl %edx, 24(%rbp)
movl 16(%rbp), %edx
movl 24(%rbp), %eax
addl %edx, %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
addq $16, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movl $1, -4(%rbp)
movl $3, -8(%rbp)
movl -8(%rbp), %edx
movl -4(%rbp), %eax
movl %eax, %ecx
call sum
movl %eax, -12(%rbp)
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"

过程详解:

补充:整个过程中虽然看不到RIP,但它一直被使用,RIP每次都指向下一条将要运行的指令

每次取出一条指令时,RIP就会自动偏移,指向下一条指令,如图:

当发生函数调用时,也就是call时,callq 指令会自动将rip压入栈,并将rip指向被调用的函数,如

先RIP指向 callq f(),下一次执行就是调用函数f(),查看此时的rsp

接着执行该指令

ip跳到了f()内的第一条指令push %rbq,再查看rsp

rsp中存入了0x00401586,正是call的下一条指令的位置

且也可以查看变量在栈帧内的存储形式

将1赋值给变量b,即mov 1 -4(%bp),查看内存

就是在bp的偏移4字节处

再来看ret,ret是将之前存的RIP给出栈,经过sub分配空间然后再add释放空间,pop rbp后,rsp刚好在旧的rip处

此时执行ret,会自动执行pop rip,也就恢复了现场

也就是说:

call f的本质是:

push %rip
mov f,%rip

ret的本质是:

pop %rip

C温故补缺(十五):栈帧的更多相关文章

  1. Kinect for Windows SDK v2.0 开发笔记 (十五) 手势帧

     (转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview1409 同前面,由于SDK未完毕,不附上函数/方法/接口的超链接. 这次最 ...

  2. “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. “全栈2019”Java多线程第二十五章:生产者与消费者线程详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  4. “全栈2019”Java多线程第十五章:当后台线程遇到finally

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  6. “全栈2019”Java第九十五章:方法中可以定义静态局部内部类吗?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. “全栈2019”Java第八十五章:实现接口中的嵌套接口

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. “全栈2019”Java第七十五章:内部类持有外部类对象

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  9. “全栈2019”Java第六十五章:接口与默认方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  10. “全栈2019”Java第五十五章:方法的静态绑定与动态绑定

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. springMVC配置时,静态资源和jsp文件路径没错但是访问时controller的请求报404错误。

    springMVC配置时,静态资源和jsp文件路径没错但是访问时controller的请求报404错误. 1.场景 如果在web.xml中servlet-mapping的url-pattern设置的是 ...

  2. Maven 过滤问题

    <build> <resources> <resource> <directory>src/main/resources</directory&g ...

  3. 常见Content-Type(MIME)列表

    Content-Type(MIME)用于标识发送或接收数据的类型,浏览器根据该参数来决定数据的打开方式.多用于指定一些客户端自定义的文件,以及一些媒体文件的打开方式. 文件扩展名 Content-Ty ...

  4. haproxy + keeplived

    两台主机: 192.168.2.163 192.168.2.165 # yum安装haproxy yum install haproxy # cat /etc/haproxy/haproxy.cfg ...

  5. Compose 模板文件

    模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多.但大家不用担心,这里面大部分指令跟 docker run 相关参数的含义都是类似的. 默认的模板文件名称为 docker-compo ...

  6. Python中class内置方法__init__与__new__作用与区别探究

    背景 最近尝试了解Django中ORM实现的原理,发现其用到了metaclass(元类)这一技术,进一步又涉及到Python class中有两个特殊内置方法__init__与__new__,决定先尝试 ...

  7. 报时机器人的rasa shell执行流程分析

      本文以报时机器人为载体,介绍了报时机器人的对话能力范围.配置文件功能和训练和运行命令,重点介绍了rasa shell命令启动后的程序执行过程. 一.报时机器人项目结构 1.对话能力范围 (1)能够 ...

  8. 关于Linux中使用bc命令计算圆周率

    Linux系统中,我们可以安装bc计算器用来计算pi值(π圆周率) 在玩的同时,这可以从某些方面反映出一个CPU的运算能力,在命令最前加上time即可 如果系统中没有bc命令,需要先进行安装:yum ...

  9. python+request+pymysql+pytest数据驱动

    一.pymysql简单使用 1.安装mysql 下载地址:https://www.mysql.com/,安装教程这里不做介绍了,网上一大推. 2.安装pymysql库 在Terminal终端输入:pi ...

  10. BUUCTF-PWN-第一页writep(32题)

    温故而知新,可以为师矣.所以花了几天时间重新做了下 buuctf 的 pwn 题,先发下第一页共 32 题的题解.还有如果题解都很详细那么本文就太长了,写起来也浪费时间,所以比较简单的题就直接丢 ex ...