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 STRLENpush strHello是把字符串长度和字符串的地址使用压栈的方式来传递参数,然后在print子程序中从栈中取出参数,就完成了参数的传递。栈内存就如下分部:

但看到print子程序代码时,不禁一想,参数压栈了,取参数STRLENstrHello时为什么不直接pop ecxpop 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 _startb print,在标号为_startprint的地方打上断点,如下图:

然后查看输入r,表示run,然后程序会执行到断点_start处停止,如下图:

查看_start标号断点执行前的情况

查看反汇编代码

此时,就可以查看_start标号的子程序代码块的内容了,输入disassemble,将此处内存的机器码反汇编,查看每一条汇编指令所在的内存地址。

上图的反汇编代码对应的源代码就是:

可以看到:

  1. STRLENstrHelloprint等标号都被替换成了具体的数值。
  2. 每一行指令的地址

可知:

  1. STRLEN = 0xd = 13,数一数代码中字符个数也正好是13;这个数在调用print时会被压栈。
  2. strHello表示字符串的地址,该地址是0x804a000,这个地址数值在调用print时会被压栈。
  3. 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执行的下一行指令的地址压栈保存,并且该栈就是进行数据操作的栈,所以在操作栈时要小心,不光自己使用pushpop指令会修改栈的内容,在使用call指令也会修改栈的内容

因此在CALL指令调用子程序,使用栈传递参数时,入参可以push 参数,取参数时可不能直接pop,因为栈顶并不是刚才传进去的参数,而是原始ip的值!

gdb调试查看CALL指令的压栈情况相关推荐

  1. java中push和pop指令的作用_汇编语言PUSH和POP指令(压栈和出栈)

    汇编里把一段内存空间定义为一个栈,栈总是先进后出,栈的最大空间为 64K.由于 "栈" 是由高到低使用的,所以新压入的数据的位置更低,ESP 中的指针将一直指向这个新位置,所以 E ...

  2. gdb调试查看内存数据

    gdb查看内存数据 格式 x /nfu f 显示方式 x 按十六进制格式显示变量. d 按十进制格式显示变量. u 按十进制格式显示无符号整型. o 按八进制格式显示变量. t 按二进制格式显示变量. ...

  3. JVM常用指令:常量,变量的压栈出栈指令

    目录 常量压栈指令 局部变量表压栈指令 操作数栈出栈指令 通用指令 上一篇日志里用到的指令如bipush,iload等都是JVM常用的指令,它们有各自的分类,如bipush是常量压入操作数栈,iloa ...

  4. GDB调试qemu-kvm

    GDB调试qemu-kvm 前面几篇博文都是记录一些kvm相关包编译安装及使用,但都没深入去代码看看.看源码在配合上相关原理才能更好的理解kvm.但qemu-kvm的代码量很多,对我来讲直接看源码收获 ...

  5. 【FFMPEG系列】之ffmpeg怎么利用gdb调试以及gdb调试快捷键

    1.编译可调试的FFmepg (1).使用命令: ./configure --enable-debug --disable-optimizations --disable-asm --disable- ...

  6. C语言函数参数压栈顺序为何是从右到左?

    #转载自:http://blog.csdn.net/jiange_zh 上学期学习了汇编语言,并在操作系统实验中使用了汇编+C语言混合编程,中间也了解了一些C语言与汇编语言的对应关系. 由于汇编语言是 ...

  7. 【软件开发底层知识修炼】十七 快速学习GDB调试四 使用GDB进行函数调用栈的查看

    上一篇文章学习了如何使用GDB数据断点进行内存监测:[软件开发底层知识修炼]十五 快速学习GDB调试三 使用GDB的数据断点监测变量是否改变 本篇文章继续上一篇文章的学习:如何使用GDB进行函数调用栈 ...

  8. gdb如何确定内存 已经释放_很经典的GDB调试命令,包括查看变量,查看内存

    转载地址:http://www.cnblogs.com/rosesmall/archive/2012/04/12/2444431.html PS:如果想跟踪正在运行的进程可以: ps 查看进程id . ...

  9. linux gdb检查函数栈,Linux - gdb调试

    调试 调试工具:gdb的使用 编译后版本 编译后的成果分为两个版本: debug版本:调试版本 -->程序员使用 release版本:最终发行版本 -->最终用户使用 gcc默认生成的是r ...

最新文章

  1. html中Marquee属性详解
  2. 织梦后台上传文章的php文件是那个,如何在织梦文章中上传视频及调用视频
  3. android 补签控件,问道手游安卓12月8日维护公告 新增补签功能
  4. Maven中安装本地Jar包到仓库中或将本地jar包上传
  5. KMP算法字符串模式匹配
  6. JS 日期工具类-基于yDate
  7. TreeMap内部实现简介
  8. 科罗拉多州立大学计算机科学专业,2020年科罗拉多州立大学有哪些优势专业
  9. win10下pytorch-gpu安装以及CUDA详细安装过程
  10. JS 中国标准时间转换yy-mm-dd HH:mm:ss
  11. 【计导非课系列】 第五节 二进制 进制计算 编码
  12. sunday算法简介
  13. linux 多播路由查看,实现Linux下多播路由
  14. python利用海伦公式求三角形的面积
  15. β射线与哪些物质可产生较高的韧致辐射_浙师大《近代物理实验》考试卷(总)...
  16. open edx 实现第三方登录-shibboleth单点登录
  17. 520用计算机二进制怎么表示,520用数学公式怎么表达
  18. 计算机窗口的跳转列表,win7[开始]菜单和任务栏最近打开的项目(跳转列表)
  19. 【机器学习】深入剖析主成分分析(PCA)与协方差矩阵
  20. 1446282-28-5,PEG5-bis-(ethyl phosphonate)含有两个乙基膦酸盐部分的PEG连接物

热门文章

  1. OPPO1107_官方线刷包_救砖包_解账户锁
  2. ES6面试、复习干货知识点汇总(全)
  3. 网络为什么会发生卡顿-2?
  4. SQLServer设置主键自增长
  5. Linux基本命令Linux基本命令
  6. 抖音做社交,答案风中飘
  7. 重庆邮电大学管理系统(统计查询)
  8. 华亚HTV903升级程序使用说明
  9. mysql支持中文设置
  10. node 导入 导出 下载excel