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,语言选择C。代码如下: #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的房屋租赁系统(前后端分离)
博主主页:猫头鹰源码 博主简介:Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容:毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…...
Python文件读写操作详解:从基础到高级
摘要:文件读写是Python编程中常见的操作之一。本文将介绍Python中文件读写的基础知识,包括打开文件、读取文件内容、写入文件、关闭文件等基本操作。此外,还将探讨一些高级文件读写技术,如使用上下文管理器、处理异常、使用with语…...
ThreadLocal基本介绍
文章目录 什么是ThreadLocalThreadLocal解决了什么问题ThreadLocal的作用 ThreadLocal的使用场景ThreadLocal的代码示例ThreadLocal的优点ThreadLocal的缺点与volatile、synchronized、ThreadLocal比较 总结 什么是ThreadLocal ThreadLocal是Java中的一个线程本地变量…...
ffmpeg源码编译成功,但是引用生成的静态库(.a)报错,报错位置在xxx_list.c,报错信息为某变量未定义
背景:本文是对上一个文章的补充,在源码编译之前,项目是有完整的ffmpeg编译脚本的,只不过新增了断点调试ffmpeg,所以产生的上面的文章,也就是说,我在用make编译成功后,再去做的源码编…...
2023爱分析·信创云市场厂商评估报告:中国电子云
01 研究范围定义 信创2.0时代开启,信创进程正在从局部到全面、从细分到所有领域延展。在这个过程中,传统的系统集成,也在逐步向信创化、数字化及智能化转变。随着信创产业的发展,企业需要更多的技术支持和服务,而传统的系统集成已…...
网络安全学习笔记——XFF攻击流程
手工注入 手动报错注入,填写格式如: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方法,在首次进入会自动监听当前的页面,在返回的时候会自动弹出弹窗阻止用户返回上一页,点击确定则返回上一页,取消则停留在当前页 onLoad: function(){wx.enableAlertBeforeUnload({…...
LangChain+ChatGLM整合LLaMa模型(二)
开源大模型语言LLaMa LLaMa模型GitHub地址添加LLaMa模型配置启用LLaMa模型 LangChainChatGLM大模型应用落地实践(一) LLaMa模型GitHub地址 git lfs clone https://huggingface.co/huggyllama/llama-7b添加LLaMa模型配置 在Langchain-ChatGLM/configs/m…...
【NLP】训练chatglm2的评价指标BLEU,ROUGE
当进行一定程度的微调后,要评价模型输出的语句的准确性。由于衡量的对象是一个个的自然语言文本,所以通常会选择自然语言处理领域的相关评价指标。这些指标原先都是用来度量机器翻译结果质量的,并且被证明可以很好的反映待评测语句的准确性&a…...
java+springboot+mysql员工工资管理系统
项目介绍: 使用javaspringbootmysql开发的员工工资管理系统,系统包含超级管理员,系统管理员、员工角色,功能如下: 超级管理员:管理员管理;部门管理;员工管理;奖惩管理&…...
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官方中文版是一个完整的软件音乐制作环境或数字音频工作站(DAW)。它代表了 25 多年的创新发展,将您创作、编曲、录…...
探索Python数据容器之乐趣:列表与元组的奇妙旅程!
文章目录 零 数据容器入门一 数据容器:list(列表)1.1 列表的定义1.2 列表的下表索引1.3 列表的常用操作1.3.1 列表的查询功能1.3.2 列表的修改功能1.3.3 列表常用方法总结 1.4 补充:append与extend对比1.5 list(列表)的遍历1.6 补…...
Python自动化实战之使用Pytest进行API测试详解
概要 每次手动测试API都需要重复输入相同的数据,而且还需要跑多个测试用例,十分繁琐和无聊。那么,有没有一种方法可以让你更高效地测试API呢?Pytest自动化测试!今天,小编将向你介绍如何使用Pytest进行API自…...
TCP的三次握手以及四次断开
TCP的三次握手和四次断开,就是TCP通信建立连接以及断开的过程 目录 【1】TCP的三次握手过程 ---- TCP建立连接的过程 【2】TCP的四次挥手 ---- TCP会话的断开 注意: 【1】TCP的三次握手过程 ---- TCP建立连接的过程 三次握手的过程:…...
目标检测YOLO实战应用案例100讲-基于视觉与激光雷达信息融合的智能车辆目标检测研究
目录 前言 传感器选型及同步 2.1 各传感器工作原理及性能对比 2.1.1 视觉传感器...
Day 22 C++ STL常用容器——string容器
string容器 概念本质string和char 区别:特点string构造函数构造函数原型 string赋值操作赋值的函数原型示例 string字符串拼接函数原型:示例 string查找和替换函数原型示例 string字符串比较比较方式 字符串比较是按字符的ASCII码进行对比函数原型示例 s…...
使用Socket实现UDP版的回显服务器
文章目录 1. Socket简介2. DatagramSocket3. DatagramPacket4. InetSocketAddress5. 实现UDP版的回显服务器 1. Socket简介 Socket(Java套接字)是Java编程语言提供的一组类和接口,用于实现网络通信。它基于Socket编程接口,提供了…...
【MCU学习】GD32F427VG开发
(一)学习文档和例程 兆易创新GD32 MCU参考资料下载 1.GD232F4xx的Keil芯片支持包 2.标准固件库和示例程序 3.GD32F4xx_固件库使用指南_Rev1.2 4.用户手册:GD32F4xx_User_Manual_Rev2.8_CN 5.数据手册:GD32F427xx_Datasheet_Rev…...
Acwing.877 扩展欧几里得算法
题目 给定n对正整数ai , bi,对于每对数,求出一组ai ,g,使其满足ai* xi bi * yi gcd(ai ,bi)。 输入格式 第一行包含整数n。 接下来n行,每行包含两个整数ai , bi。 输出格式 输出共n行,对于每组ai, bi,…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
