gdb调试查看CALL指令的压栈情况
gdb调试查看CALL指令的压栈情况
文章目录
- gdb调试查看CALL指令的压栈情况
- CALL指令时压栈
- 使用gdb调试验证CALL指令压栈情况
- 查看_start标号断点执行前的情况
- 查看反汇编代码
- 查看print标号断点执行前的情况
- 查看栈段的内容
- 结论
CALL指令时压栈
有这样一段代码,功能是输出字符串,代码如下:
section .data
strHello db "Hello World!", 0Ah
STRLEN equ $-strHellosection .textglobal _start
_start:push STRLENpush strHellocall printmov ebx, 0
mov eax, 1
int 0x80print:mov ecx, [esp+4] ; 为什么是4,为什么不直接pop ecxmov edx, [esp+8] ; 为什么是8,为什么不pop edx; 发起sys_write()系统调用,输出信息mov ebx, 1 mov eax, 4int 0x80ret
上述代码,把输出字符串的代码放到一个子程序print
中,然后在调用print
子程序时,字符串的地址和字符串的长度通过栈来传递。
粗略地一看很简单也没毛病,在call print
前,push STRLEN
和push strHello
是把字符串长度和字符串的地址使用压栈的方式来传递参数,然后在print
子程序中从栈中取出参数,就完成了参数的传递。栈内存就如下分部:
但看到print
子程序代码时,不禁一想,参数压栈了,取参数STRLEN
和strHello
时为什么不直接pop ecx
和pop edx
呢?
然后又看了一下取参数的下标,代码中是mov edx, [esp+8]
和mov ecx, [esp+4]
,strHello
不是应该在栈顶吗,不应该是直接取吗?
当查看了课本之后,才发现,在使用call指令调用子程序时,相当于修改了程序走向,要修改ip的值,因此需要把原来ip的值压栈保存,当子程序调用完毕后在把ip的值恢复。
所以,在call print
前,ip会指向mov ebx, 0
(call指令的下一个指令),那么当执行call指令,就会把这个地址压栈,也就是栈空间分布其实是这样的:
可是书上,写的是“相当于”,是真的就是把ip的值压栈吗?是指SS:SP
那个栈吗?
所以我想在程序运行中验证下栈的数据,确认下当call指令执行完,栈顶是不是那个原先的mov ebx, 0
(call指令的下一个指令)的地址。
使用gdb调试验证CALL指令压栈情况
这里再贴一边代码:
section .data
strHello db "Hello World!", 0Ah
STRLEN equ $-strHellosection .text
global _start
_start:push STRLENpush strHellocall printmov ebx, 0
mov eax, 1
int 0x80print:mov ecx, [esp+4] ; 为什么是4,为什么不直接pop ecxmov edx, [esp+8] ; 为什么是8,为什么不pop edx; 发起sys_write()系统调用,输出信息mov ebx, 1 mov eax, 4int 0x80ret
将上述的汇编代码生成可执行程序(可调试的,使用参数-g指定):
输入gdb hello
进入gdb调试,对hello进行调试。
进入gdb调试页面,输入b _start
,b print
,在标号为_start
和print
的地方打上断点,如下图:
然后查看输入r
,表示run,然后程序会执行到断点_start
处停止,如下图:
查看_start标号断点执行前的情况
查看反汇编代码
此时,就可以查看_start
标号的子程序代码块的内容了,输入disassemble
,将此处内存的机器码反汇编,查看每一条汇编指令所在的内存地址。
上图的反汇编代码对应的源代码就是:
可以看到:
STRLEN
,strHello
,print
等标号都被替换成了具体的数值。- 每一行指令的地址
可知:
- STRLEN = 0xd = 13,数一数代码中字符个数也正好是13;这个数在调用print时会被压栈。
- strHello表示字符串的地址,该地址是0x804a000,这个地址数值在调用print时会被压栈。
- call指令的下一条指令(
mov ebx, 0
)的地址是0x0804900c
查看print标号断点执行前的情况
执行到print
标号处,是call print
指令已经执行完毕了,已经进入print
子程序了,ip已经指向了print
子程序第一条指令,该指令欲执行。
也就是此时,进入print
子程序了,_start
程序中的下面的三条指令都执行完毕:
push STRLEN
push strHello
call print
查看栈段的内容
此时查看栈段的值,要想知道栈的内容,要先知道esp的值:
上图可知,栈顶指针的地址是0xffffce94,由于栈是往下走的,因此栈顶在低地址,栈底在高地址。
所以,查看地址0xffffce94处连续2个word(1 word = 4 byte)和1个h(1 h = 2 byte),因为在压栈时,STRLEN应该是2个字节,strHello是一个地址占4个字节,压入旧的eip的值也是4个字节。所以预想的栈内存分布图应该如下:
所以接下来只需验证下栈的内容和图中预想是不是一样的即可。
gdb中查看栈的内容(这里为了方便,直接看栈顶连续三个word的内容算了):
x/3xw 0xffffce94
注:0xfffce94是栈顶指针ESP的值,上面图中有。
栈中内容显示结果如下:
可知,此时实际内存中,栈的内容应该是这样的:
在看看上面提到的_start
标号处汇编指令执行过程中的地址情况:
栈中的内容,和我们对CALL指令压栈的猜想完全一致。
结论
所以最终结论是,在调用call 子程序
指令时,会把call执行的下一行指令的地址压栈保存,并且该栈就是进行数据操作的栈,所以在操作栈时要小心,不光自己使用push
、pop
指令会修改栈的内容,在使用call
指令也会修改栈的内容。
因此在CALL指令调用子程序,使用栈传递参数时,入参可以push 参数
,取参数时可不能直接pop
,因为栈顶并不是刚才传进去的参数,而是原始ip的值!
gdb调试查看CALL指令的压栈情况相关推荐
- java中push和pop指令的作用_汇编语言PUSH和POP指令(压栈和出栈)
汇编里把一段内存空间定义为一个栈,栈总是先进后出,栈的最大空间为 64K.由于 "栈" 是由高到低使用的,所以新压入的数据的位置更低,ESP 中的指针将一直指向这个新位置,所以 E ...
- gdb调试查看内存数据
gdb查看内存数据 格式 x /nfu f 显示方式 x 按十六进制格式显示变量. d 按十进制格式显示变量. u 按十进制格式显示无符号整型. o 按八进制格式显示变量. t 按二进制格式显示变量. ...
- JVM常用指令:常量,变量的压栈出栈指令
目录 常量压栈指令 局部变量表压栈指令 操作数栈出栈指令 通用指令 上一篇日志里用到的指令如bipush,iload等都是JVM常用的指令,它们有各自的分类,如bipush是常量压入操作数栈,iloa ...
- GDB调试qemu-kvm
GDB调试qemu-kvm 前面几篇博文都是记录一些kvm相关包编译安装及使用,但都没深入去代码看看.看源码在配合上相关原理才能更好的理解kvm.但qemu-kvm的代码量很多,对我来讲直接看源码收获 ...
- 【FFMPEG系列】之ffmpeg怎么利用gdb调试以及gdb调试快捷键
1.编译可调试的FFmepg (1).使用命令: ./configure --enable-debug --disable-optimizations --disable-asm --disable- ...
- C语言函数参数压栈顺序为何是从右到左?
#转载自:http://blog.csdn.net/jiange_zh 上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系. 由于汇编语言是 ...
- 【软件开发底层知识修炼】十七 快速学习GDB调试四 使用GDB进行函数调用栈的查看
上一篇文章学习了如何使用GDB数据断点进行内存监测:[软件开发底层知识修炼]十五 快速学习GDB调试三 使用GDB的数据断点监测变量是否改变 本篇文章继续上一篇文章的学习:如何使用GDB进行函数调用栈 ...
- gdb如何确定内存 已经释放_很经典的GDB调试命令,包括查看变量,查看内存
转载地址:http://www.cnblogs.com/rosesmall/archive/2012/04/12/2444431.html PS:如果想跟踪正在运行的进程可以: ps 查看进程id . ...
- linux gdb检查函数栈,Linux - gdb调试
调试 调试工具:gdb的使用 编译后版本 编译后的成果分为两个版本: debug版本:调试版本 -->程序员使用 release版本:最终发行版本 -->最终用户使用 gcc默认生成的是r ...
最新文章
- html中Marquee属性详解
- 织梦后台上传文章的php文件是那个,如何在织梦文章中上传视频及调用视频
- android 补签控件,问道手游安卓12月8日维护公告 新增补签功能
- Maven中安装本地Jar包到仓库中或将本地jar包上传
- KMP算法字符串模式匹配
- JS 日期工具类-基于yDate
- TreeMap内部实现简介
- 科罗拉多州立大学计算机科学专业,2020年科罗拉多州立大学有哪些优势专业
- win10下pytorch-gpu安装以及CUDA详细安装过程
- JS 中国标准时间转换yy-mm-dd HH:mm:ss
- 【计导非课系列】 第五节 二进制 进制计算 编码
- sunday算法简介
- linux 多播路由查看,实现Linux下多播路由
- python利用海伦公式求三角形的面积
- β射线与哪些物质可产生较高的韧致辐射_浙师大《近代物理实验》考试卷(总)...
- open edx 实现第三方登录-shibboleth单点登录
- 520用计算机二进制怎么表示,520用数学公式怎么表达
- 计算机窗口的跳转列表,win7[开始]菜单和任务栏最近打开的项目(跳转列表)
- 【机器学习】深入剖析主成分分析(PCA)与协方差矩阵
- 1446282-28-5,PEG5-bis-(ethyl phosphonate)含有两个乙基膦酸盐部分的PEG连接物