当前位置: 首页 > news >正文

C语言代码的x86-64汇编指令分析过程记录

先通过Xcode创建一个terminal APP,语言选择C。代码如下:

#include <stdio.h>int main(int argc, const char * argv[]) {int a[7]={1,2,3,4,5,6,7};int *ptr =(int*)(&a+1);printf("%d\n",*(ptr));return 0;
}

在return 0处打上断点,并且选择Xcode菜单Debug|Debug Workflow|Always Show Disassembly,然后run。这时候断点会调到汇编代码里。得到汇编代码如下:

Terminal`main:0x100003ec0 <+0>:   pushq  %rbp0x100003ec1 <+1>:   movq   %rsp, %rbp0x100003ec4 <+4>:   subq   $0x50, %rsp0x100003ec8 <+8>:   movq   0x131(%rip), %rax         ; (void *)0x00007ff84ef2f8a0: __stack_chk_guard0x100003ecf <+15>:  movq   (%rax), %rax0x100003ed2 <+18>:  movq   %rax, -0x8(%rbp)0x100003ed6 <+22>:  movl   $0x0, -0x34(%rbp)0x100003edd <+29>:  movl   %edi, -0x38(%rbp)0x100003ee0 <+32>:  movq   %rsi, -0x40(%rbp)0x100003ee4 <+36>:  movq   0xa5(%rip), %rax0x100003eeb <+43>:  movq   %rax, -0x30(%rbp)0x100003eef <+47>:  movq   0xa2(%rip), %rax0x100003ef6 <+54>:  movq   %rax, -0x28(%rbp)0x100003efa <+58>:  movq   0x9f(%rip), %rax0x100003f01 <+65>:  movq   %rax, -0x20(%rbp)0x100003f05 <+69>:  movl   0x9d(%rip), %eax0x100003f0b <+75>:  movl   %eax, -0x18(%rbp)0x100003f0e <+78>:  leaq   -0x30(%rbp), %rax0x100003f12 <+82>:  addq   $0x1c, %rax0x100003f16 <+86>:  movq   %rax, -0x48(%rbp)0x100003f1a <+90>:  movq   -0x48(%rbp), %rax0x100003f1e <+94>:  movl   (%rax), %esi0x100003f20 <+96>:  leaq   0x85(%rip), %rdi          ; "%d\n"0x100003f27 <+103>: movb   $0x0, %al0x100003f29 <+105>: callq  0x100003f5a               ; symbol stub for: printf0x100003f2e <+110>: movq   0xcb(%rip), %rax          ; (void *)0x00007ff84ef2f8a0: __stack_chk_guard0x100003f35 <+117>: movq   (%rax), %rax0x100003f38 <+120>: movq   -0x8(%rbp), %rcx0x100003f3c <+124>: cmpq   %rcx, %rax0x100003f3f <+127>: jne    0x100003f4d               ; <+141> at main.c
->  0x100003f45 <+133>: xorl   %eax, %eax0x100003f47 <+135>: addq   $0x50, %rsp0x100003f4b <+139>: popq   %rbp0x100003f4c <+140>: retq   0x100003f4d <+141>: callq  0x100003f54               ; symbol stub for: __stack_chk_fail0x100003f52 <+146>: ud2    

首先介绍下面会用到的几个寄存器:

rip :程序计数寄存器
rsp : 栈指针寄存器,指向栈顶
rbp : 栈基址寄存器,指向栈底
edi : 函数参数
rsi/esi : 函数参数
eax : 累加器或函数返回值用

1、 pushq %rbp
将rbp的地址压栈,rsp继续指向栈顶

2、 movq %rsp, %rbp
将栈顶rsp的值赋值给栈底rbp,

3、 subq $0x50, %rsp
栈顶往下移5*16个字节,可以理解成给后面预留的80字节的空间。X64中栈开辟的大小都是0x10的倍数。

4、movq   0x131(%rip), %rax         ; (void *)0x00007ff84ef2f8a0: __stack_chk_guard

0x131(%rip)的意思是下一条指令的地址(0x100003ecf)加上0x131得到目标地址(0x100004000),然后取得其中的8字节值,设置给rax寄存器。

选中Debug workflow|View Memory,在Address里输入‘0x100004000’然后回车,我们可以看到此处的内容为0x00007ff84ef2f8a0(注意大小端问题):

 5、movq   (%rax), %rax

从rax寄存器存放的地址处取得值,并传给rax寄存器。类似前面的操作,我们发现此处的值为0x55d1d55afee700d6:

 6、movq   %rax, -0x8(%rbp)

现在把rax中的值,也就是上面这个图上所示的8个字节,存入rbp-0x8的位置。我们先打印下rbp和rsp的值,然后跳到rsp处查看内存:

 

红框处即是我们存放值的地方。右边8字节则是rbp指向的位置。

7、movl   $0x0, -0x34(%rbp)

将4字节0设置到rbp-0x34的位置,这里的目的是将下一条指令中-0x38(%rbp)的高字节清零。该位置为0x7ff7bfeff3ac:

 8、movl   %edi, -0x38(%rbp)

该命令保存edi寄存器的值到rbp-0x38位置,也就是上图的0x7ff7bfeff3a8,值是1。前面我们说edi是用来保存函数参数的,也就是int argc,在这个例子中argc的值为1,所以edi寄存器的值为1。

9、movq   %rsi, -0x40(%rbp)

该命令保存rsi寄存器的值到rbp-0x40位置,也就是上图的0x7ff7bfeff3a0,值是0x7ff7bfeff518。这里是参数argv的值0x7ff7bfeff708。由于argv是const char **,因此这也是个地址值,我们前往该地址查看其内容。

10、movq   0xa5(%rip), %rax

 获取位于0x100003eeb+0xa5=0x100003f90处的8字节内容,然后存入rax寄存器:

 11、movq   %rax, -0x30(%rbp)

 将rax寄存器的值存入rbp-0x30的位置:

12-17跟上面两步相同,就是存3,4,5,6,7的值,注意7是单独存的,因为movl表示4字节,而movq代表8字节,也就是2个int。

0x100003eef <+47>:  movq   0xa2(%rip), %rax0x100003ef6 <+54>:  movq   %rax, -0x28(%rbp)0x100003efa <+58>:  movq   0x9f(%rip), %rax0x100003f01 <+65>:  movq   %rax, -0x20(%rbp)0x100003f05 <+69>:  movl   0x9d(%rip), %eax0x100003f0b <+75>:  movl   %eax, -0x18(%rbp)

18、leaq   -0x30(%rbp), %rax

获取rbp-0x30=0x7ff7bfeff3b0,然后存入rax寄存器。

19、addq   $0x1c, %rax

将rax寄存器中的值0x7ff7bfeff3b0,加上0x1c后(0x7ff7bfeff3cc)存入rax寄存器。这里对应代码`int *ptr =(int*)(&a+1);`0x1c是28,也就是数组的大小28字节,说明指针的加法是在编译阶段将数值替换为具体的值,也就是该值乘以指针类型大小后的值。

20、movq   %rax, -0x48(%rbp)

接下去把rax的值0x7ff7bfeff3cc存入rbp-0x48的位置:

 21、movq   -0x48(%rbp), %rax

接着又把刚存入的这个值存入寄存器rax

22、movl   (%rax), %esi

把rax寄存器所存地址对应的值(1)存入寄存器esi,这是作为下面要调用的print方法的第二个参数。

 23、leaq   0x85(%rip), %rdi          ; "%d\n"

rip=0x100003f27,加上0x85后为0x100003fac,然后设置给rdi寄存器,也就是print调用的第一个参数。0x100003fac这个位置的值刚好是字符串"%d\n"。

 24、movb   $0x0, %al

将立即数0存储到al寄存器中。那么如何理解eax,ax,al(ah)之间的关系
专业点可以这样解释:eax是32位寄存器,ax是16位寄存器,al(ah)是八位寄存器。

对于变长参数的函数,要用%al指明用到的vector registers的个数 ,比如printf,这里我们没有用到可变参数,所以要给al寄存器设置0。参考:Why are the %al register and stack modified before calling printf x86 assembly from C "Hello World" program compiled by gcc

汇编函数调用的参数传递 

 25、callq  0x100003f5a               ; symbol stub for: printf

调用printf函数。call有一个作用:将call指令的下一条指令地址压栈:

 

26、movq   0xcb(%rip), %rax          ; (void *)0x00007ff84ef2f8a0: __stack_chk_guard

27、movq   (%rax), %rax

26和27步骤跟4和5处类似,这里不再赘述。

28、movq   -0x8(%rbp), %rcx

将栈底8字节存入rcx寄存器

29、cmpq   %rcx, %rax

比较rcx寄存器和rax寄存器的值是否相等,并把结果写入状态寄存器

30、jne    0x100003f4d               ; <+141> at main.c

如果29的比较结果为不相等,就跳转0x100003f4d处继续执行,也就是35处。相等的话执行31处。这里主要是使用__stack_chk_guard_ptr来判断是否发生栈溢出,导致栈底开始8字节被篡改。可以参考關於__stack_chk_guard_ptr的理解

31、xorl   %eax, %eax

将eax寄存器清零,作为main函数的return值

32、addq   $0x50, %rsp

这句正好对应前面的subq $0x50, %rsp。通过给栈顶指针加上开辟栈的大小,回收栈顶指针开辟的空间。

33、popq   %rbp

这句指令表示出栈,同时将出栈的值放入寄存器rbp

34、retq

这句表示退出main函数,会恢复rip值。本例没有体现这一点,由main函数的调用者保存rip。

35、callq  0x100003f54               ; symbol stub for: __stack_chk_fail

调用__stack_chk_fail函数

36、ud2

UD2 指令的字节编码为 0F 0B,它是一个两字节的指令。在汇编语言中,可以使用 UD2 指令来实现一些特殊的功能,比如触发调试断点或者中断程序的执行。 UD2 指令常用于调试程序。具体可查看:ud2 汇编指令

最终的栈布局

相关文章:

C语言代码的x86-64汇编指令分析过程记录

先通过Xcode创建一个terminal APP&#xff0c;语言选择C。代码如下&#xff1a; #include <stdio.h>int main(int argc, const char * argv[]) {int a[7]{1,2,3,4,5,6,7};int *ptr (int*)(&a1);printf("%d\n",*(ptr));return 0; } 在return 0处打上断点&…...

基于springboot+vue的房屋租赁系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...

Python文件读写操作详解:从基础到高级

摘要&#xff1a;文件读写是Python编程中常见的操作之一。本文将介绍Python中文件读写的基础知识&#xff0c;包括打开文件、读取文件内容、写入文件、关闭文件等基本操作。此外&#xff0c;还将探讨一些高级文件读写技术&#xff0c;如使用上下文管理器、处理异常、使用with语…...

ThreadLocal基本介绍

文章目录 什么是ThreadLocalThreadLocal解决了什么问题ThreadLocal的作用 ThreadLocal的使用场景ThreadLocal的代码示例ThreadLocal的优点ThreadLocal的缺点与volatile、synchronized、ThreadLocal比较 总结 什么是ThreadLocal ThreadLocal是Java中的一个线程本地变量&#xf…...

ffmpeg源码编译成功,但是引用生成的静态库(.a)报错,报错位置在xxx_list.c,报错信息为某变量未定义

背景&#xff1a;本文是对上一个文章的补充&#xff0c;在源码编译之前&#xff0c;项目是有完整的ffmpeg编译脚本的&#xff0c;只不过新增了断点调试ffmpeg&#xff0c;所以产生的上面的文章&#xff0c;也就是说&#xff0c;我在用make编译成功后&#xff0c;再去做的源码编…...

2023爱分析·信创云市场厂商评估报告:中国电子云

01 研究范围定义 信创2.0时代开启&#xff0c;信创进程正在从局部到全面、从细分到所有领域延展。在这个过程中&#xff0c;传统的系统集成,也在逐步向信创化、数字化及智能化转变。随着信创产业的发展&#xff0c;企业需要更多的技术支持和服务&#xff0c;而传统的系统集成已…...

网络安全学习笔记——XFF攻击流程

手工注入 手动报错注入&#xff0c;填写格式如&#xff1a;X-Forwarded-For: and updatexml(1,concat(0x7e,(select database()),0x7e),1) or 11 库名 1 and updatexml(1,concat(0x7e,database(),0x7e),1), 表名 1 and updatexml(1,concat(0x7e,(select table_name from…...

微信小程序阻止用户返回上一页,并弹窗给用户确定是否要返回上一页

在onload中调用微信的enableAlertBeforeUnload方法&#xff0c;在首次进入会自动监听当前的页面&#xff0c;在返回的时候会自动弹出弹窗阻止用户返回上一页&#xff0c;点击确定则返回上一页&#xff0c;取消则停留在当前页 onLoad: function(){wx.enableAlertBeforeUnload({…...

LangChain+ChatGLM整合LLaMa模型(二)

开源大模型语言LLaMa LLaMa模型GitHub地址添加LLaMa模型配置启用LLaMa模型 LangChainChatGLM大模型应用落地实践&#xff08;一&#xff09; LLaMa模型GitHub地址 git lfs clone https://huggingface.co/huggyllama/llama-7b添加LLaMa模型配置 在Langchain-ChatGLM/configs/m…...

【NLP】训练chatglm2的评价指标BLEU,ROUGE

当进行一定程度的微调后&#xff0c;要评价模型输出的语句的准确性。由于衡量的对象是一个个的自然语言文本&#xff0c;所以通常会选择自然语言处理领域的相关评价指标。这些指标原先都是用来度量机器翻译结果质量的&#xff0c;并且被证明可以很好的反映待评测语句的准确性&a…...

java+springboot+mysql员工工资管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的员工工资管理系统&#xff0c;系统包含超级管理员&#xff0c;系统管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;部门管理&#xff1b;员工管理&#xff1b;奖惩管理&…...

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版

FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows FL Studio Producer Edition 21 v21.0.3 Build 3517 Windows/mac官方中文版是一个完整的软件音乐制作环境或数字音频工作站&#xff08;DAW&#xff09;。它代表了 25 多年的创新发展&#xff0c;将您创作、编曲、录…...

探索Python数据容器之乐趣:列表与元组的奇妙旅程!

文章目录 零 数据容器入门一 数据容器&#xff1a;list(列表)1.1 列表的定义1.2 列表的下表索引1.3 列表的常用操作1.3.1 列表的查询功能1.3.2 列表的修改功能1.3.3 列表常用方法总结 1.4 补充&#xff1a;append与extend对比1.5 list&#xff08;列表&#xff09;的遍历1.6 补…...

Python自动化实战之使用Pytest进行API测试详解

概要 每次手动测试API都需要重复输入相同的数据&#xff0c;而且还需要跑多个测试用例&#xff0c;十分繁琐和无聊。那么&#xff0c;有没有一种方法可以让你更高效地测试API呢&#xff1f;Pytest自动化测试&#xff01;今天&#xff0c;小编将向你介绍如何使用Pytest进行API自…...

TCP的三次握手以及四次断开

TCP的三次握手和四次断开&#xff0c;就是TCP通信建立连接以及断开的过程 目录 【1】TCP的三次握手过程 ---- TCP建立连接的过程 【2】TCP的四次挥手 ---- TCP会话的断开 注意&#xff1a; 【1】TCP的三次握手过程 ---- TCP建立连接的过程 三次握手的过程&#xff1a…...

目标检测YOLO实战应用案例100讲-基于视觉与激光雷达信息融合的智能车辆目标检测研究

目录 前言 传感器选型及同步 2.1 各传感器工作原理及性能对比 2.1.1 视觉传感器...

Day 22 C++ STL常用容器——string容器

string容器 概念本质string和char 区别&#xff1a;特点string构造函数构造函数原型 string赋值操作赋值的函数原型示例 string字符串拼接函数原型&#xff1a;示例 string查找和替换函数原型示例 string字符串比较比较方式 字符串比较是按字符的ASCII码进行对比函数原型示例 s…...

使用Socket实现UDP版的回显服务器

文章目录 1. Socket简介2. DatagramSocket3. DatagramPacket4. InetSocketAddress5. 实现UDP版的回显服务器 1. Socket简介 Socket&#xff08;Java套接字&#xff09;是Java编程语言提供的一组类和接口&#xff0c;用于实现网络通信。它基于Socket编程接口&#xff0c;提供了…...

【MCU学习】GD32F427VG开发

&#xff08;一&#xff09;学习文档和例程 兆易创新GD32 MCU参考资料下载 1.GD232F4xx的Keil芯片支持包 2.标准固件库和示例程序 3.GD32F4xx_固件库使用指南_Rev1.2 4.用户手册&#xff1a;GD32F4xx_User_Manual_Rev2.8_CN 5.数据手册&#xff1a;GD32F427xx_Datasheet_Rev…...

Acwing.877 扩展欧几里得算法

题目 给定n对正整数ai , bi&#xff0c;对于每对数&#xff0c;求出一组ai ,g&#xff0c;使其满足ai* xi bi * yi gcd(ai ,bi)。 输入格式 第一行包含整数n。 接下来n行&#xff0c;每行包含两个整数ai , bi。 输出格式 输出共n行&#xff0c;对于每组ai, bi&#xff0c…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

是否存在路径(FIFOBB算法)

题目描述 一个具有 n 个顶点e条边的无向图&#xff0c;该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序&#xff0c;确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数&#xff0c;分别表示n 和 e 的值&#xff08;1…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...