C温故补缺(十五):栈帧
栈帧
概念
栈帧:也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构,每次函数的调用,都会在调用栈(call stack)上维护一个独立的栈帧(stack frame)
栈帧的内容
函数的返回地址和参数
临时变量:包括函数的非静态局部变量,以及编译器自动生成的其他临时变量
函数调用上下文
两个指针:ebp又称帧指针(frame pointer),指向当前栈帧的底部; esp,又称栈针织(stack pointer),始终指向栈顶
函数调用
函数调用过程中分:函数调用者(caller)和被调用的函数(callee)
调用者需要知道被调用函数的返回值
被调用函数需要知道传入的参数和返回的地址
步骤:
参数入栈:将参数按照调用约定依次压入系统栈
返回地址入栈:将当前代码区调用指令的下一条指令地址压入栈,供函数返回时继续执行,也就是保护现场和恢复现场
代码跳转:处理器将代码区跳转到被调用函数的入口处
栈帧调整:
将调用者的ebp压入栈,保存指向栈底ebp地址(用于恢复现场),此时esp指向新的栈顶位置
将当前栈帧切换到新栈帧(将esp值装入ebp,跟新栈底),此时ebp指向栈顶,
给新栈帧分配空间
函数返回
步骤:
保存被调用函数的返回值到eax寄存器
恢复esp同时收回局部变量空间
将上一个栈帧底部位置恢复到ebp
弹出当前元素栈顶元素,从栈中取到返回地址,并跳转到该位置,也就是再回到调用者,执行后续代码
举例说明
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温故补缺(十五):栈帧的更多相关文章
- Kinect for Windows SDK v2.0 开发笔记 (十五) 手势帧
(转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview1409 同前面,由于SDK未完毕,不附上函数/方法/接口的超链接. 这次最 ...
- “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第二十五章:生产者与消费者线程详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第十五章:当后台线程遇到finally
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java异常第十五章:异常链详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- “全栈2019”Java第九十五章:方法中可以定义静态局部内部类吗?
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第八十五章:实现接口中的嵌套接口
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第七十五章:内部类持有外部类对象
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第六十五章:接口与默认方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第五十五章:方法的静态绑定与动态绑定
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
随机推荐
- 【读书笔记】C#高级编程 第二十章 诊断
(一)诊断概述 名称空间System.Diagnostics提供了用于跟踪.事件日志.性能测量以及代码协定的类.System.Diagnostics.Contracts名称空间中的类可以定义前提条件. ...
- Ansible_基础模块
特点:无主从,即装即用,基于ssh 安装ansible yum install epel-release -y yum install ansible -y 定义主机清单 vim /etc/ansib ...
- 高阶 CSS 技巧在复杂动效中的应用
最近我在 CodePen 上看到了这样一个有意思的动画: 整个动画效果是在一个标签内,借助了 SVG PATH 实现.其核心在于对渐变(Gradient)的究极利用. 完整的代码你可以看看这里 -- ...
- 利用 Gitea Doctor自助诊断工具帮助管理员排查问题
我常常在Gitea论坛或者Hostea为网友解答Gitea版本升级方面的问题,但发现少有人知道利用 gitea doctor 命令行工具排查问题,因此这篇博文将给大家带来通俗易懂的介绍. 你知道吗? ...
- 一文带你体验MRS HetuEngine如何实现跨源跨域分析
摘要: HetuEngine作为MRS服务中交互式分析&多源统一SQL引擎,亲自全程体验其如何实现多数据源的跨源跨域分析能力. 本文分享自华为云社区<MRS HetuEngine体验跨源 ...
- SVM公式详尽推导,没有思维跳跃。
假定数据集\(T=\{(x_1,y_1),(x_2,y_2),...,(x_n,y_n)\},x_n \in R_k, y_n \in \{1,-1\}\)线性可分,SVM的优化目标是: 优化一个超平 ...
- 记录一次Bitbucket鉴权的坑
目录 发生了什么 什么原因 如何解决 总结 发生了什么 今天首次在Fedora上使用git,因为没有小王八(TortoiseGit)帮助,其过程异常焦灼-- 反正经过一系列折腾,我在本地新建了一个项目 ...
- PHP全栈开发(八):CSS Ⅶ 表格 style
表格默认是没有边框的,因此,我们在设置表格格式的时候,首先要设置的是表格边框的样式,也就是 table{ border-style:solid; } 设置完表格表格的样式之后,可以设置表格边框的粗细程 ...
- mysql 过程和函数语法学习笔记
CREATE DEFINER=`root`@`%` PROCEDURE `test`(`num` int) BEGIN /*定义变量*/ DECLARE sex TINYINT(2) DEFAULT ...
- day48-JDBC和连接池04-2
JDBC和连接池04-2 10.数据库连接池 10.5Apache-DBUtils 10.5.1resultSet问题 先分析一个问题 在之前的程序中,执行sql语句后返回的结果集存在如下问题: 关闭 ...