从汇编层看64位程序运行——函数的调用和栈平衡

news2024/11/15 17:53:08

函数调用

不知道有没有人想过一个问题:A函数调用B函数,B函数是如何知道在调用结束后回到A函数中的?

比如下面的代码,main函数调用foo。当foo执行完毕,需要执行main函数的return 0语句。但是main和foo是割裂的,foo是怎么回到main函数中继续执行的呢?

void foo() {
    int a = 10;
    a = a + 5;
}

int main() {
    foo();
    return 0;
}

我们对上述代码进行反汇编。
在main函数中,我们没有看到任何蛛丝马迹,只看到call指令。
在这里插入图片描述
上图显示,当前代码执行到+8处(但是此行并没有执行,它的上一行执行了)。我们需要注意它的地址以及其后的地址0x0000555555555364,即+18处。理论上说,foo函数执行完毕后,CPU会执行+18处的代码。我们将通过调试来查看具体的原因。
让程序运行到+13处,可以看到当前rsp和rbp值相同,都是0x7fffffffdf10。
在这里插入图片描述
进入foo函数内部,可以看到call指令导致rsp减少了4字节,即有一个4字节值被call指令push到栈中。
在这里插入图片描述
通过下面指令,我们看到被push进来的值是0x0000555555555364。
在这里插入图片描述
我们反汇编这个地址附近代码,可以发现call指令将当前函数返回到的代码地址给push到栈中。这样foo函数在执行完毕后,就可以在栈中取出该地址,从而跳转到此处继续执行,完成从foo函数到main函数的跳跃。
在这里插入图片描述

栈平衡

栈平衡是指函数调用子函数后,栈顶要回到没有准备调用子函数之前。
在函数调用前后,涉及压栈操作的有如下情况:

  • call指令会将本函数中下条要执行的指令地址push到栈中
  • 如果子函数超过6个参数,则从第7个参数开始的参数会通过栈来传递

以下面的代码为例,

void foo10(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) {
    a = a + 5;
    b = b + 5;
    c = c + 5;
    d = d + 5;
    e = e + 5;
    f = f + 5;
    g = g + 5;
    h = h + 5;
    i = i + 5;
    j = j + 5;
    int sum = a + b + c + d + e + f + g + h + i + j;
    sum = sum + 5;
}

int main() {
    int a = 10;
    int b = 20;
    int c = 30;
    int d = 40;
    int e = 50;
    int f = 60;
    int g = 70;
    int h = 80;
    int i = 90;
    int j = 100;
    foo10(a, b, c, d, e, f, g, h, i, j);
    return 0;
}

其中main函数的反汇编结果如下
在这里插入图片描述
我们来通过动态调试,来查看上述代码如何做到栈平衡。
我们让代码执行到+105处,查看此时rsp寄存器和栈上数据
在这里插入图片描述
然后让其他参数入栈,可以看到栈增加了0x20。(即rsp的值减少了0x20,0x7fffffffdef0->0x7fffffffded0)
在这里插入图片描述
进入foo10函数后,call导致的Next RIP压栈会在其ret时弹出。于是foo10执行完毕回到main函数后,rsp的值还不处于栈平衡状态。
在这里插入图片描述
但是紧接着foo10函数的调用,main函数会通过下面的命令让栈获得平衡
在这里插入图片描述
在这里插入图片描述
总体来说,栈的失衡是函数调用导致的,且发生在调用者函数中;栈的再平衡则是在子函数退出,执行回到调用者函数时立即执行的。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【排序 】

目录 1, 排序的概念及引用 1.1 排序的概念 1.2 常见的排序算法 2, 常见排序算法的实现 2.1 插入排序 2.1.1基本思想: 2.1.2 直接插入排序 2.1.3 希尔排序( 缩小增量排序 )(面试很少问) 2.2 选择排序 2.2.1基本思想: 2.…

Java巅峰之路---基础篇---综合练习(面向对象)

目录 文字版格斗游戏 基础版 souf输出语句 进阶版 键盘录入的说明 复杂对象数组练习 需求: 添加和遍历 删除和遍历 修改和遍历 文字版格斗游戏 基础版 格斗游戏,每个游戏角色的姓名,血量,都不相同,在选定人…

2024最新Cloudways主机使用教程(含最新Cloudways折扣码)

Cloudways是一家提供云托管服务的公司,可以帮助你轻松管理和运行你的网站。本教程是Cloudways主机注册和使用教程。Cloudways界面简洁,使用方便,不需要复杂的设置,就能快速搭建一个WordPress网站。它的主机功能包括高级缓存和Bree…

Linux命令更新-Vim 编辑器

简介 Vim 是 Linux 系统中常用的文本编辑器,功能强大、可扩展性强,支持多种编辑模式和操作命令,被广泛应用于程序开发、系统管理等领域。 1. Vim 命令模式 Vim 启动后默认进入命令模式,此时键盘输入的命令将用于控制编辑器本身&…

QT控件篇三

一、微调框 微调框(QSpinBox)是一个常用的Qt控件,允许用户通过增加或减少值来输入数字。分为两种, 整型-QSpinBox 浮点 QDoubleSpinBoxQSpinBox(微调框)的 setSingleStep 函数可以用来设置每次调整的步长(…

Kafka基础入门-代码实操

Kafka是基于发布/订阅模式的消息队列,消息的生产和消费都需要指定主题,因此,我们想要实现消息的传递,第一步必选是创建一个主题(Topic)。下面我们看下在命令行和代码中都是如何创建主题和实现消息的传递的。…

TDesign组件库日常应用的一些注意事项

【前言】Element(饿了么开源组件库)在国内使用的普及率和覆盖率高于TDesign-vue(腾讯开源组件库),这也导致日常开发遇到组件使用上的疑惑时,网上几乎搜索不到其文章解决方案,只能深挖官方文档或…

Python编程工具PyCharm和Jupyter Notebook的使用差异

在编写Python程序时需要用到相应的编程工具,PyCharm和Jupyter Notebook是最常用2款软件。 PyCharm是很强大的综合编程软件,代码提示、代码自动补全、语法检验、文本彩色显示等对于新手来说实在太方便了,但在做数据分析时发现不太方便&#xf…

UGUI优化篇(更新中)

UGUI优化篇 1. 基础概念2. 重要的类1. MaskableGraphic类继承了IMaskable类2. 两种遮罩的实现区别RectMask2DMask 3. 渲染部分知识深度测试深度测试的工作原理 渲染队列透明物体在渲染时怎么处理为什么透明效果会造成性能问题 1. 基础概念 所有UI都由网格绘制的如image由两个三…

成为CMake砖家(2): macOS创建CMake本地文档的app

大家好,我是白鱼。 使用 CMake 的小伙伴, 有的是在 Windows 上, 还有的是在 macOS 上。之前咱们讲了 windows 上查看 cmake 本地 html 文档的方式, 这篇讲讲 macOS 上查看 cmake 本地 html 文档的方法。 1. 问题描述 当使用 CMa…

数模·图论

matlab中图的表示 顶点集权值集的形式 s是源点,t是终点,w是对应的权值 调用graph(s,t,w)作为参数创建图 调用plot函数绘图plot(G,EdgeLabel,G.Edges.Weight,LineWidth,2) 设置x和y的坐标范围set(gca,XTick,[],YTick,[]) s[1 2 3]; t[4 1 2]; w[5 2 6]; …

程序包不存在【java: 程序包org.springframework.boot不存在】

1、问题提示:java: 程序包org.springframework.boot不存在 注意:已经下载好了程序包,就是提示不存在 2、解决办法

一个开源完全免费的无损视频或音频的剪切/裁剪/分割/截取和视频合并工具

大家好,今天给大家分享一款致力于成为顶尖跨平台FFmpeg图形用户界面应用的软件工具LosslessCut。 LosslessCut是一款致力于成为顶尖跨平台FFmpeg图形用户界面应用的软件工具,专为实现对视频、音频、字幕以及其他相关媒体资产的超高速无损编辑而精心打造。…

《后端程序猿 · EasyPOI 导入导出》

📢 大家好,我是 【战神刘玉栋】,有10多年的研发经验,致力于前后端技术栈的知识沉淀和传播。 💗 🌻 CSDN入驻不久,希望大家多多支持,后续会继续提升文章质量,绝不滥竽充数…

蓝桥杯嵌入式第十五届模拟考试3解析

1 题目 2 程序 /* USER CODE BEGIN PTD */ char buf1[20],buf2[20],buf3[20],buf4[20],buf5[20],buf6[20],buf7[20],buf8[20],buf9[20]; struct keys {int step;int length;int state; }key[5]; int display; double v1,v2; int t; double v1l1.2,v1u2.2,v2l1.4,v2u3.0; dou…

深度学习复盘与论文复现D

文章目录 一、新环境搭建与适应1、easy_install和pip的安装使用2、关于安装包超时的解决方案3、brew安装包安装4、使用新环境运行以前项目5、解决win的pycharm修改内存后无法启动 二、Dataset 数据读取问题1、Lightning Torch 读取数据2、Pytorch的DataLoader数据读取机制3、Py…

Dify中的经济索引模式实现过程

当索引模式为经济时,使用离线的向量引擎、关键词索引等方式,降低了准确度但无需花费 Token。 一.提取函数**_extract** 根据不同文档类型进行内容的提取: def _extract(self, index_processor: BaseIndexProcessor, dataset_document: Data…

力扣经典题目之->移除值为val元素的讲解,的实现与讲解

一:题目 博主本文将用指向来形象的表示下标位的移动。 二:思路 1:两个整形,一个start,一个end,在一开始都 0,即这里都指向第一个元素。 2:在查到val之前,查一个&…

C语言 ——— 将一句英语短句中的单词进行倒置

目录 题目要求 代码实现 题目要求 将一句英语短句中的单词进行倒置&#xff0c;标点符号不倒置 如&#xff1a; 输入&#xff1a;"I like chongqing very much," 输出&#xff1a;"much, very chongqing like I" 代码实现 #include<stdio.h> #i…

c#与欧姆龙PLC通信——如何更改PLC的IP地址

前言 我们有时候需要改变欧姆龙Plc的ip地址,下图有两种更改方式,一种是已知之前Plc设置的Ip地址,还有一种是之前不知道Pl的Ip地址是多少,下面分别做介绍。 1、已知PLC的IP地址的情况下更改地址 假设已知PLC的Ip地址,比如本文中PLC的IP为192.168.1.2,我首先将电脑的IP地…