当前位置: 首页 > 编程日记 > 正文

汇编语言系统调用过程

以printf为例,详细解析一个简单的printf调用里头,系统究竟做了什么,各寄存器究竟如何变化。

如何在汇编调用glibc的函数?其实也很简单,根据c convention call的规则,参数反向压栈,call,然后结果保存在eax里头。注意,保存的是地址。

在汇编里头,一切皆地址。


当我们调用 result = printf( "%d %d", 12, a )的时候,编译器默认是这样处理的(除非函数定义声明了pascal call)。

在栈里头,先一次push a的地址,还有12这个立即数,再push "%d %d"这个字符串的地址,内存模型如下,x86的esp是往下增长的。

(这里是buttom,往下增长的是top)

&a

12

address of "%d %d"

-------------------------------------------(esp 指着这里 ,我们假设地址是4字节,12这个数也是4字节)

当call printf的时候,首先,push当前的eip入esp,解析esp+4所指的"%d %d",因为%d这样的特定字符都定义了后面每个参数的大小,所以只要解析“%d %d”,我们就可以知道栈里头参数的情况,例如esp+4+4就是一个int,esp+4+4+4是另外一个int。

当返回的时候,先pop到eip,也就是把eip还原到call之后马上要执行的机器码,这时,esp就指着“%d %d”,esp+4指着12,esp+8指着a的地址。esp里头的内容怎么处理,看需要吧,你也可以pop出来,也可以不pop。但为了效率着想,如果空间够用,通常不pop,直接用mov指令把下一次要用的参数move进去。返回指储存在eax里头。


这也一定程度上解释了为什么c convention call是反向压栈,这样编译器处理起来方便,特别对于这些va_list,因为va_list后面不能继续跟参数,va_list一定出现在函数的末尾,如果是对printf这类的函数使用pascal call,也就是参数正向压栈,汇编级别处理起来就特别麻烦了。


下面就用汇编语言写一个调用printf,并用gdb跟踪寄存器。


代码test_printf.s

.section .data            
format: .asciz "%d\n" 
.section .text    
.global _start    
_start:            
pushl $12            
pushl $format         
call printf         
movl $0, (%esp)            
call exit

编译

#as -g test_printf.s -o test_printf.o

链接

#ld -lc -I /lib/ld-linux.so.2 test_printf.o -o test_printf

-g是要加入调试信息

ld的-lc是链接libc.a,-I是--dynamic-linker,/lib/ld-linux.so.2

运行

#./test_printf

输出12


调试

用objdump看看test_printf里头的.text section,注意Disassembly of section .text


使用gdb跟踪,看看上述是否正确

#gdb test_printf

设置断点到_start

(gdb) break _start

(gdb) run

执行,遇到断点,停下,eip指着第6行,也就是第一条要执行的push指令

(gdb) info reg

察看寄存器状况

(gdb) s

执行一步,eip指着下一条指令地址

(gdb) info reg


esp 0xbffff6cc 0xbffff6cc

6cc = 6d0 - 4,对比上一条的esp,小了4,也就是stack增长了4个字节


(gdb) s

(gdb) info reg

esp 0xbffff6c8 0xbffff6c8

6c8 = 6cc - 4,对比上一条的esp,小了4,也就是stack增长了4个字节


(gdb) s

in printf () from /lib/libc.so.6

执行一步,正式进入printf

(gdb) info reg

esp 0xbffff6c4 0xbffff6c4

6c4=6c8-4 新push进去4个字节


(gdb) x /1x $esp
0xbffff6c4: 0x080481c4

esp的栈顶保存的是下一条要执行的代码的位置,movl的位置,(参考上面objdump的结果)

可以使用bt查看栈帧,下面对比栈变化

(gdb) s

printf出12,已经执行完毕

(gdb) info reg

eax保存着这次printf的返回值,也就是被打印的字符数量,12\n,一共3个字符。

esp恢复到call printf之前的状态

恢复eip


(gdb) s

执行movl指令,下一条是call exit

(gdb) x /1x $esp

esp并没有增长,因为printf之前的数据已经没用了,我没有把他们pop出来,而是直接用新的数据刷写esp所指的内存。


(gdb) s
(gdb) s

正常退出


关于EIP、ESP、EBP寄存器

1.EIP寄存器里存储的是CPU下次要执行的指令的地址

也就是调用完fun函数后,让CPU知道应该执行main函数中的printf("函数调用结束")语句了。

2.EBP寄存器里存储的是是栈的栈底指针,通常叫栈基址,这个是一开始进行fun()函数调用之前,由ESP传递给EBP的。(在函数调用前你可以这么理解:ESP存储的是栈顶地址,也是栈底地址。)

3.ESP寄存器里存储的是在调用函数fun()之后,栈的栈顶。并且始终指向栈顶。

堆栈是一种简单的数据结构,是一种只允许在其一端进行插入或删除的线性表。
允许插入或删除操作的一端称为栈顶,另一端称为栈底,对堆栈的插入和删除操作被称入栈出栈

有一组CPU指令可以实现对进程的内存实现堆栈访问。其中,POP指令实现出栈操作,PUSH指令实现入栈操作。
CPU的ESP寄存器存放
当前线程的栈顶指针
EBP寄存器中保存
当前线程的栈底指针
CPU的EIP寄存器存放
下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。

参考:http://blog.csdn.net/feng_zh/article/details/7075986

相关文章:

switch语句中在case块里声明变量会遇到提示“Expected expression before...的问题

switch语句中在case块里声明变量会遇到提示“Expected expression before..."的问题 例如在如下代码中 1case constant:2 int i 1;3 int j 2;4 self.sum i j;5 break;GCC在case语句之后的第一行中声明变量时遇到问题。 这时需要在case块两端添加花括号&am…

帮AI体检看病一条龙服务,阿里发布“AI安全诊断大师”

如同一些出生免疫力就有缺陷的人一样,AI也存在免疫力缺陷。基于从源头打造安全免疫力的新一代安全架构理念,最近,阿里安全研究发布了一项核心技术“AI安全诊断大师”,可对AI模型全面体检,“看诊开方”,让AI…

Spring学习总结(7)——applicationContext.xml 配置文详解

web.xml中classpath:和classpath*: 有什么区别? classpath:只会到你的class路径中查找找文件; classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找. 存放位置: 1:src下面 需要在web.xml中定义如下&…

GDB查看栈信息

栈:是程序存放数据内存区域之一,特点是LIFO(后进先出)。 PUSH:入栈 POP:出战 使用场景: 1.保存动态分配的自动变量使用栈 2.函数调用时,用栈传递函数参数,半寸返回地址…

数据库学习之路

今天迎来入冬的第二场雪,闲来无事就整理了下总结下工作以来所有数据库方面的书籍和资料,发现了不少,很多已经读过或者正在读的书籍,oracle真的很强大,直到现在发现才入门的水平,当然很多书读一遍是不行的&a…

为什么铺天盖地都是Python的广告?

最近,知乎关于Python有一个热议问题: 甚至在抖音上,笔者有一次还看到Python占领了热搜!应该有很多不懂技术的吃瓜群众也被Python的热度炒懵了……但是,Python真的值得学吗?真的值得花这么多钱去学吗&#x…

python3正则表达式符号和用法

转载于:https://www.cnblogs.com/wumac/p/5441322.html

从寄存器看I386和x64位中函数调用中参数传递

x86_64基本使用寄存器存储函数参数,寄存器不够才入栈; 而i386将所有参数保存在栈上,通过gcc的扩展功能__attribute__((regparm()))即可实现部分参数的寄存器传递。 调试语法: --《深入理解计算机系统(原书第2版)》 代码 #incl…

转:去掉Flex4生成的SWF加载时的进度条

方法一&#xff1a; <?xml version"1.0" encoding"utf-8"?> <s:Application xmlns:fx"http://ns.adobe.com/mxml/2009" xmlns:s"library://ns.adobe.com/flex/spark" xmlns:mx"library://ns.adobe.com/f…

饿了么交易系统5年演化史

作者 | 挽晴来源 | 阿里巴巴中间件&#xff08;ID&#xff1a;Aliware_2018&#xff09;个人简介:2014年12月加入饿了么&#xff0c;当时参与后台系统的研发(WalisJavis>Walle)&#xff0c;主要面向客服和BD。2015年5月开始接触订单系统的研发&#xff0c;7月负责订单研发组…

Python迁移MySQL数据到MongoDB脚本

MongoDB是一个文档数据库&#xff0c;在存储小文件方面存在天然优势。随着业务求的变化&#xff0c;需要将线上MySQL数据库中的行记录&#xff0c;导入到MongoDB中文档记录。 一、场景&#xff1a;线上MySQL数据库某表迁移到MongoDB&#xff0c;字段无变化。 二、Python模块&am…

使用valgrind分析C程序调用线路图

Valgrind可以检测内存泄漏和内存违例&#xff0c;但是用Valgrind生成的日志信息结合kcachegrind就可以查看C程序的执行线路图&#xff0c;调用时间&#xff0c;是做性能优化和查看代码的非常好的工具。 1.下载安装 Valgrind 安装 到www.valgrind.org下载最新版valgrind # wg…

纯CSS实现蓝色圆角下拉菜单

代码简介&#xff1a; 这个菜单没有使用任何的图片&#xff0c;完全是用CSS实现的&#xff0c;包括圆角效果也同样是&#xff0c;而且还考虑了多浏览器的兼容性&#xff0c;可以说非常不错&#xff0c;既兼容性好&#xff0c;又外观漂亮&#xff0c;下拉导航菜单目前比较流行&a…

生产型机器学习已经没那么困难了?

作者 | Caleb Kaiser译者 | 香槟超新星出品 | CSDN&#xff08;ID:CSDNnews&#xff09;封面图源自视觉中国在软件工程的诸多领域内&#xff0c;生产用例是相当标准化的。以Web开发为例&#xff0c;要在Web应用中实现身份认证&#xff0c;你不会去创造一个数据库&#xff0c;自…

poj1330Nearest Common Ancestors 1470 Closest Common Ancestors(LCA算法)

LCA思想&#xff1a;http://www.cnblogs.com/hujunzheng/p/3945885.html 在求解最近公共祖先为问题上&#xff0c;用到的是Tarjan的思想&#xff0c;从根结点开始形成一棵深搜树&#xff0c;非常好的处理技巧就是在回溯到结点u的时候&#xff0c;u的子树已经遍历&#xff0c;这…

干货 | 时间序列预测类问题下的建模方案探索实践

作者 | 陆春晖责编 | Carol出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;背景时间序列类问题是数据分析领域中一类常见的问题&#xff0c;人们有时需要通过观察某种现象一段时间的状态&#xff0c;来判断其未来一段时间的状态。而时间序列就是该种现象某一个统计指…

Redis安装与源码调试

linux版本&#xff1a;64位CentOS 6.5 Redis版本&#xff1a;redis-3.0.6 (更新到2016年1月22日) Redis官网&#xff1a;http://redis.io/ Redis常用命令&#xff1a;http://redis.io/commands 1.安装Redis # wget http://download.redis.io/releases/redis-3.2.6.tar.g…

system pause in C#

方法一&#xff1a; Console.Write("Press any key to continue . . . "); Console.ReadKey(true); 注&#xff1a;也可用ReadLine()或Read()&#xff0c;但是只能对回车进行响应&#xff0c;不能达到anykey的效果。 方法二&#xff1a; 1) 在源文件using处加入using…

C#设置当前程序通过IE代理服务器上网

注意&#xff1a;以下设置只在当前程序中有效&#xff0c;对IE浏览器无效&#xff0c;且关闭程序后&#xff0c;自动释放代码。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices;public static …

计算机科学精彩帖子收集

linux源码 LXR 源自“the Linux Cross Referencer”&#xff0c;中间的“X”形象地代表了“Cross”。与 Source Navigator 类似&#xff0c;它也是分析阅读源代码的好工具。不同的是&#xff0c;它将源代码借助浏览器展示出来&#xff0c;文件间的跳转过程成了我熟悉的点击超链…

挑战王者荣耀“绝悟” AI,我输了!

作者 | 马超责编 | 伍杏玲出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;腾讯 AI Lab 与王者荣耀联合研发的策略协作型AI&#xff0c;“绝悟”首次开放大规模开放&#xff1a;5月1日至4日&#xff0c;玩家从王者荣耀大厅入口&#xff0c;进入“挑战绝悟”测试&…

java 注解类说明

一、类中注解 SuppressWarnings ("serial"); 关键字 用途deprecation使用了不赞成使用的类或方法时的警告unchecked执行了未检查的转换时的警告&#xff0c;例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型。fallthrough当 Switch 程序块直接通往下一种…

《ArcGIS Runtime SDK for Android开发笔记》——(13)、图层扩展方式加载Google地图...

1、前言 http://mt2.google.cn/vt/lyrsm225000000&hlzh-CN&glcn&x420&y193&z9&sGalil 通过图层扩展类的方式加载Google地图的是我们通常获取Google地图的一种方式&#xff0c;根据这种方式我们可以通过拼接地图瓦片Url字符串获取瓦片数据&#xff0c;关…

调试JDK源码-一步一步看HashMap怎么Hash和扩容

调试JDK源码-一步一步看HashMap怎么Hash和扩容 调试JDK源码-ConcurrentHashMap实现原理 调试JDK源码-HashSet实现原理 调试JDK源码-调试JDK源码-Hashtable实现原理以及线程安全的原因 还是调试源码最好。 开发环境 JDK1.8NetBeans8.1 说明&#xff1a;调试HashMap的 publ…

开源一年,阿里轻量级AI推理引擎MNN 1.0.0正式发布

在经过充分的行业调研后&#xff0c;阿里淘系技术部认为当时的推理引擎如TFLite不足以满足手机淘宝这样一个亿级用户与日活的超级App。于是&#xff0c;他们从零开始自己搭建了属于阿里巴巴的推理引擎MNN。1年前&#xff0c;MNN在Github上开源&#xff0c;截止目前获得了3.9k S…

人生在成败中进步

参考文献《佛经》 人生在成败中进步佛经中有云&#xff1a;“菩萨者&#xff0c;福慧深利&#xff0c;道观双流。”“福慧双修”、“福慧双全”是众生成佛的必由之道&#xff0c;也是众生修行的理想追求。人生中&#xff0c;虽然不可能人人都能成佛&#xff0c;但是佛经有云&am…

【原】YUI压缩与CSS media queries下的bug

大概是上个月&#xff0c;使用YUI压缩一个css文件后&#xff0c;发现只要是被压缩后的css文件有部分根本无法工作&#xff0c;一直都不知啥问题引起的&#xff0c;让我感到头疼。 今天发现了只要是在媒体查询中的样式无法起作用&#xff0c;于是才开始怀疑是media被压缩后引起的…

Spring源码分析【4】-Spring扫描basePackages注解

org.springframework.beans.factory.support.DefaultListableBeanFactory 重要数据结构 /** Map of bean definition objects, keyed by bean name */private final Map<String, BeanDefinition> beanDefinitionMap new ConcurrentHashMap<String, BeanDefinition&…

c语言c++语言中静态变量,函数详解

静态变量&#xff0c;静态函数对于一些c&#xff0c;c的初学者来说&#xff0c;造成了不少的困扰。昨晚和寝室的室友讨论到这 个问题&#xff0c;想了一下&#xff0c;作了一下总结&#xff1a;虽然说c和c在很多人的眼里就是孪生姐妹&#xff0c;其实还是有很大区别的。在这里分…

深度解析MegEngine亚线性显存优化技术

基于梯度检查点的亚线性显存优化方法[1]由于较高的计算/显存性价比受到关注。MegEngine经过工程扩展和优化&#xff0c;发展出一套行之有效的加强版亚线性显存优化技术&#xff0c;既可在计算存储资源受限的条件下&#xff0c;轻松训练更深的模型&#xff0c;又可使用更大batch…