从汇编看函数调用

文章目录

    • 函数调用流程
    • 栈相关寄存器及的作用简介
      • 寄存器功能
      • 指令功能
    • 函数的括号{}
      • 正括号
      • 反括号
    • 参数传递
        • 传值,变量不可改
        • 传指针,变量可改
        • C++ 传引用
    • 函数调用实例

函数调用流程

目标:函数调用前后栈保持不变
在这里插入图片描述

  1. 保存main函数的寄存器上下文
  2. 移动栈指针,到新栈
  3. 调用新函数:新函数会开辟内存然后操作
  4. 恢复栈指针

栈相关寄存器及的作用简介

寄存器功能

在这里插入图片描述ESP/RSP:堆栈指针寄存器,指向栈顶。栈顶指针
EBP/RBP:栈底指针,指向栈的底部,通常用ebp+偏移量的形式来定位函数存放在栈中的局部变量

rax:通常用于存储函数调用返回值
rdi:第一个入参
rsi:第二个入参
rdx:第三个入参
rcx:第四个入参
r8:第五个入参
r9:第六个入参

寄存器ebp作为当前函数的“栈帧”基地址,配合一定的偏移,就可以读、写函数体的临时变量。如果一个变量是通过ebp寄存器间接访问的,那么它往往是临时变量,也叫“栈”变量。

指令功能

在这里插入图片描述
在这里插入图片描述

push rbp 保存上下文,保存rbp值
1.rbp里面的值放到当前rsp指向的位置,保存当前栈底指针的值
2. 然后rsp–,栈顶指针向上移动

pop eax 恢复栈帧
1. 栈顶指针向下移动,这里的值保存的是原函数的栈底位置
2. ebp指向esp里面值的位置,移动栈底指针到原函数位置

在这里插入图片描述
call
1. 会把call指令的下一条指令压入栈,把下一条指令的地址,也就是函数func的返回地址(0x401105e)压入堆栈
2.CPU跳转到函数func的首地址。
在这里插入图片描述在这里插入图片描述

栈是存储临时数据的区域,在普通内存中,它的特点是通过push指令和pop指令进行数据的存储和读出。往栈中存储数据称为“入栈”,从栈中读出数据称为“出栈”。32位x86系列的CPU中,进行1次push或pop,即可处理32位(4字节)的数据。push指令和pop指令中只有一个操作数。该操作数表示的是“push的是什么及pop的是什么”,而不需要指定“对哪一个地址编号的内存进行push或pop”。
这是因为,对栈进行读写的内存地址是由esp寄存器(栈指针)进行管理的。push指令和pop指令运行后,esp寄存器的值会自动进行更新(push指令是-4, pop命令是+4),因而程序员就没有必要指定内存地址了。

栈是由大地址向小地址递减,而堆和普通内存是小地址到大地址递增

操作系统会为每个任务(进程或线程)分配一段内存当作任务“堆栈”;CPU则提供两个寄存器esp、ebp,用来标识当前函数对“堆栈”的使用情况。随着函数的逐层调用,函数的“栈帧”会逐次堆叠,互不重合;随着函数的逐层返回,函数的“栈帧”会被就地放弃,但不会清理内存

函数的括号{}

其实函数的调用主要部分就是正反括号的内容
正负括号都对应两条指令。
在这里插入图片描述

正括号

先看正括号,三条指令,作用是保存原栈,并分配新的栈空间

  1. push rbp : push指令把寄存器ebp的值压入“栈顶”,然后将“栈顶”红色水位线(CPU寄存器esp)上移,扩大栈空间。至此,main函数的“栈帧”保护工作完成!
  2. 然后通过mov指令,更新一下“栈帧”基准线,让ebp指向esp,这里就是新的func的栈了
    在这里插入图片描述

反括号

然后看反括号两条指令:反括号作用是恢复栈

  1. pop, 把事先压入“栈顶”的ebp值返还给CPU寄存器ebp。这样蓝色基准线就恢复到了最开始的位置。然后esp红色水位线也随之下降。esp和ebp的值就都恢复了。
  2. ret指令,把“栈顶”处的返回值传给CPU寄存器rip,这样,CPU就可以跳转到主调函数main被打断的地方0x401105e继续执行了。

参数传递

先看下传递参数的汇编:
在这里插入图片描述

  1. 传值调用和传指针其实都是将值传递到函数中,只不过这个值含义不同指针是一个地址的值。
  2. 还可以看出用作传参的寄存器是哪几个。
传值,变量不可改

我们接着看函数中,对参数赋值的汇编:
在这里插入图片描述1. 这里会将参数寄存器中的值,放入栈中。然后释放参数寄存器。
2. 然后将内存地址数据赋值。
3. 这也就说明原来参数的值被复制了一份到内存中,修改当前形参的值,实际是修改栈中内存的值,原变量不会被修改

传指针,变量可改

在这里插入图片描述

  1. 首先还是将参数的值放入内存中,释放寄存器
  2. 然后将参数x的内存地址传给寄存器,寄存器当前存储的是该地址
  3. 然后向该寄存器中存储的地址中,写入0.
    这也就直接修改了内存中原变量的值,这里的寄存器rax起到了一个中间过渡作用。

Q:为什么传递参数是通过CPU寄存器,而不是直接压入堆栈呢?
A:传递参数,也可以不通过CPU寄存器,而通过压入堆栈的方式,一些老版本的编译器,也是如此操作的。但通过寄存器传递,可以避免一些内存操作,一定程度上有利于提高函数的执行效率。

C++ 传引用

C++ 传引用和传指针的汇编相同,所以传引用只是一个语法糖
在这里插入图片描述

函数调用实例

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/296691.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用MySQL和PHP创建一个公告板

目录 一、创建表 二、制作首页(创建主题以及显示列表) 三、制作各个主题的页面(输入回帖和显示列表) 四、制作消息的查询界面 五、制作读取数据库信息的原始文件 六、制作数据重置页面 七、效果图 八、问题 1、目前无法处…

商务电子邮件: 在WorkPlace中高效且安全

高效和安全的沟通是任何组织成功的核心。在我们关于电子邮件类型的系列文章的第二期中,我们将重点关注商业电子邮件在促进无缝交互中的关键作用。当你身处重要的工作场环境时,本系列的每篇文章都提供了电子邮件的不同维度的视角。 “2024年,全…

基于springboot实现房屋租赁管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现房屋租赁系统演示 摘要 房屋是人类生活栖息的重要场所,随着城市中的流动人口的增多,人们对房屋租赁需求越来越高,为满足用户查询房屋、预约看房、房屋租赁的需求,特开发了本基于Spring Boot的房屋租赁系统。 …

保健品wordpress外贸模板

保健品wordpress外贸模板 健康保养保健品wordpress外贸模板,做大健康行业的企业官方网站模板。 https://www.jianzhanpress.com/?p3514

防火墙状态检测和会话机制

FW对TCP,UDP和ICMP协议的报文创建会话

【如何解决一些常见的 Composer 错误的保姆级讲解】

🌈个人主页:程序员不想敲代码啊🌈 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家🏆 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提…

如何使用免费的ChatGpt3.5

如何使用免费的ChatGpt 最近免费的gpt3.5很多都不怎么行了实在是太给力了尾声 最近免费的gpt3.5很多都不怎么行了 原因是什么呢?因为openai已经取消了免费的5刀赠送,那么这些人手上的免费的sses-key 用完后,就基本上全军覆没了,再…

在 Amazon Timestream 上通过时序数据机器学习进行预测分析

由于不断变化的需求和现代化基础设施的动态性质,为大型应用程序规划容量可能会非常困难。例如,传统的反应式方法依赖于某些 DevOps 指标(如 CPU 和内存)的静态阈值,而这些指标在这样的环境中并不足以解决问题。在这篇文…

vscode + wsl1 搭建远程C/C++开发环境

记录第一次搭建环境过程。 搭建C/C开发环境有很多种方式,如 MinGW vscode(MinGW 是GCC的Windows版本,本地编译环境)SSH隧道连接 vscode(远程Linux主机)wsl vscode(远程Linux环境&#xff09…

flink1.18源码本地调试环境

01 源码本地调试环境搭建 1. 从github拉取源码创建本地项⽬ https://github.com/apache/flink.git 可以拉取github上官⽅代码 https://github.com/apache/flink.git GitHub - apache/flink: Apache Flink 2. 配置编译环境 ctrlaltshifts (或菜单)打…

node.js的错误处理

当我打开一个不存在的文件时,错误如下: 在读取文件里面写入console.log(err),在控制台中可以看到我的错误代码类型:文件不存在的错误代码 ENOENT。见更多错误代码---打开node.js官方API文档Error 错误 | N…

Redhat 7.9 安装dm8配置文档

Redhat 7.9 安装dm8配置文档 一 创建用户 groupadd -g 12349 dinstall useradd -u 12345 -g dinstall -m -d /home/dmdba -s /bin/bash dmdba passwd dmdba二 创建目录 mkdir /dm8 chown -R dmdba:dinstall /dm8三 配置/etc/security/limits.conf dmdba soft nproc 163…

Springboot Thymeleaf 实现数据添加、修改、查询、删除

1、引言 在Spring Boot中使用Thymeleaf模板引擎实现数据的添加、修改、查询和删除功能,通常步骤如下: 在Controller类中,定义处理HTTP请求的方法。创建Thymeleaf模板来处理表单的显示和数据的绑定。 2、用户数据添加 1、 在Controller类中…

【javaScript】DOM编程入门

一、什么是DOM编程 概念:DOM(Document Object Model)编程就是使用document对象的API完成对网页HTML文档进行动态修改,以实现网页数据和样式动态变化的编程 为什么要由DOM编程来动态修改呢?我们就得先理解网页的运行原理: 如上图&a…

达梦配置ODBC连接

达梦配置ODBC连接 基础环境 操作系统:Red Hat Enterprise Linux Server release 7.9 (Maipo) 数据库版本:DM Database Server 64 V8 架构:单实例1 下载ODBC包 下载网址:https://www.unixodbc.org/ unixODBC-2.3.0.tar.gz2 编译并…

C++的并发世界(六)——互斥解决数据共享冲突

0.数据共享的问题 在多个线程中共享数据时。需要注意线程安全问题。如果多个线程同时访问同一个变量。并且其中至少有一个线程对该变量进行了写操作。那么就会出现数据竞争问题。数据竞争可能会导致程序崩溃,产生来定义的结果,或者得到错误的热果。为了避免数据竞争问题。需要…

Java快速入门系列-1(Java概述)

第一章:Java概述 1.1 Java的发展历程1.2 Java的特点与优势1.2.1 特点1.2.2 优势 1.3 Java生态系统介绍1.4 Java在当前技术领域的应用案例 1.1 Java的发展历程 Java语言由Sun Microsystems公司于1995年推出,由James Gosling领导的Green Team小组研发而成…

SpringCloud - 如何本地调试不会注册到线上环境(Nacos)?

问题描述 有时候我们需要本地调试注册到 Nacos 上,但是会影响线上服务的 Feign 请求打到本地导致不通影响了线上业务。 原因分析 一般最传统的解决方案就是修改本地 bootstrap.yml 的 spring.cloud.nacos.discovery.namespace spring:application:name: app-serv…

【调度工具】Azkaban用户手册

目录 一、概述 1.1 Azkaban 是什么 1.2 Azkaban 特点 1.3 Azkaban 与 Oozie 对比 功能 工作流定义 工作流传参 定时执行 资源管理 工作流执行 工作流管理 1.4 Azkaban 运行模式及架构 Azkaban 三大核心组件 Azkaban有两种部署方式 Azkaban Web Server Azkaban …

基于Python深度学习的中文情感分析系统(V2.0)

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…