之前在看汇编的时候一直是肉眼看GCC -S的结果,缺点是很不直观,无法实时的看到寄存器的值,所以研究了下如何用GDB调试汇编。当然,写这篇文章更重要的一个目的是半年没有写博客了,博客要长草了。^_^

调试汇编的需求有几点:

  • 能够单步进行汇编调试。
  • 能够实时看到寄存器值的变化。
  • 能够看到源代码和对应汇编的关系。

下面分享下用GDB实现上面的3点需求:

单步进行汇编调试

使用si和ni。与s与n的区别在于:s与n是C语言级别的单步调试,si与ni是汇编级别的单步调试。

能够实时看到寄存器值的变化。

使用gdb时增加-tui选项,打开gdb后运行layout regs命令。注意最好加上-tui,否则很大可能会出现花屏现象。

能够看到源代码和对应汇编的关系

在gdb中运行set disassemble-next-line on,表示自动反汇编后面要执行的代码。

可以清晰的看出int c=sum(x,y);与下面红框内的汇编指令成对应关系。

如果大家不想用这么原始的方式,可以给GDB安装插件或者使用emacs达到上面的目的,推荐两篇文章:

  • GDB 从裸奔到穿戴整齐
  • GDB实用插件(peda, gef, gdbinit)全解

最后以一个小例子结束:

int sum(int x,int y){return x+y;
}int main(){int x=10;int y=20;int c=sum(x,y);return 0;
}

gcc版本4.4.7,默认的优化选项。

我们单步调试下这段代码对应的汇编:

设置断点

注意如果想要把断点设置在汇编指令层次函数的开头,应该使用b *fun而不是b func,这里我们把断点设置在b *main

分配栈帧

0x0000000000400489 <main+0>:   55 push   %rbp
0x000000000040048a <main+1>:  48 89 e5   mov    %rsp,%rbp
0x000000000040048d <main+4>:  48 83 ec 10    sub    $0x10,%rsp

%rbp和%rsp表示的是当前栈帧的栈底和栈顶。其中%rbp是被调用者需要保存的寄存器。sub $0x10,%rsp表示为main函数分配栈帧空间。
注意这里分配了16字节的栈空间,会有4字节用不上,我个人猜测跟gcc汇编产生的cfi_def_cfa_offset 16有关,这个没有深究。

int x=10

0x0000000000400491 <main+8>:    c7 45 f4 0a 00 00 00   movl   $0xa,-0xc(%rbp)

将x的值放到栈中

int y=20

0x0000000000400498 <main+15>:         c7 45 f8 14 00   00 00   movl   $0x14,-0x8(%rbp)

将y的值放到栈中

sum函数调用

0x000000000040049f <main+22>:         8b 55 f8  mov    -0x8(%rbp),%edx0x00000000004004a2 <main+25>:         8b 45 f4 mov    -0xc(%rbp),%eax0x00000000004004a5 <main+28>:         89 d6    mov    %edx,%esi0x00000000004004a7 <main+30>:         89 c7  mov    %eax,%edi0x00000000004004a9 <main+32>:         e8 c6 ff ff ff callq  0x400474 <sum>

将x与y分别赋值到%esi和%edi中,其中%edi和%esi被规定用来传递函数的第一个和第二个参数。(一个疑问是为什么不能直接mov -0x8(%rbp),%esi呢?)
callq会将下一条指令的地址压入栈中,并跳到sum函数的第一条指令。

进入sum函数

0x0000000000400474 <sum+0>:   55 push   %rbp
0x0000000000400475 <sum+1>:   48 89 e5   mov    %rsp,%rbp
0x0000000000400478 <sum+4>:   89 7d fc   mov    %edi,-0x4(%rbp)
0x000000000040047b <sum+7>:   89 75 f8   mov    %esi,-0x8(%rbp)

同main函数一样,首先将%rbp保存,然后从%edi和%esi中取出函数参数。

求和

0x000000000040047e <sum+10>:     8b 45 f8   mov    -0x8(%rbp),%eax
0x0000000000400481 <sum+13>:  8b 55 fc   mov    -0x4(%rbp),%edx
0x0000000000400484 <sum+16>:  8d 04 02   lea    (%rdx,%rax,1),%eax

将x和y相加,这里用到的是lea指令,关于lea指令介绍参考LEA instruction? ,这里不赘述了。
将返回值放到%eax中,%rax寄存器规定存放函数的返回值。像GO语言如果函数可以有多个返回值的话,返回值是放到栈中。

sum函数收尾

0x0000000000400487 <sum+19>:    c9 leaveq
0x0000000000400488 <sum+20>:  c3 retq

我们先看下现在的栈:

(这里不知道为什么没有sub xx,$rsp,我猜测是gcc发现这个最后一次函数调用,之后不会有栈的增长只会有栈的回退,所以用%rsp和%rbp的结果是一样的。简单验证了下,应该是这样)。
在函数结束时首先需要回收当前函数的栈帧、恢复保存过的寄存器、恢复%rip的值,即返回地址。

leaveq指令相当于:

mov  %rbp,%rsp
pop %rbp

作用是释放(deallocate)当前函数的栈帧并恢复被保存的寄存器的值。由此我们也可以看出%rbp的作用:记住%rsp应该回退的位置,否则函数结束时%rsp不知道该回退到哪。

retq指令相当于:

pop %rip

将上面保存过的callq的下一条指令地址恢复到%rip中。

接收函数返回值

0x00000000004004ae <main+37>:         89 45 fc    mov    %eax,-0x4(%rbp)

将%eax的值放入到main函数的栈帧中。

return 0

0x00000000004004b1 <main+40>:         b8 00 00 00 00   mov    $0x0,%eax

同上面sum函数一样。

main函数收尾

0x00000000004004b6 <main+45>:         c9   leaveq
0x00000000004004b7 <main+46>:         c3 retq

如果上面%rsp和%rbp指向同一内存区域看起来不太直观的话,看下现在main函数即将结束时的栈空间:

同上面sum函数的解释一样,不再赘述。

程序运行成功退出。

gdb tui 安装_GDB 单步调试汇编相关推荐

  1. Emacs + gdb单步调试汇编代码

    1.编译 # gcc -g test.c -o test2.使用emacs单步调试汇编和C对照 # emacs M-x gdb M-x gdb-many-windows //把某个窗口替换成反汇编或者 ...

  2. 用QEMU模拟调试裸机ARM64汇编,支持gdb单步调试

    完全是方便自己查询,做个记录. 树莓派4的SOC是ARM64, cortex A72,支持最新的ARMv8指令集,且有众多的开源资料,适合用来学习ARM64汇编,其他芯片大同小异,遇到需要,再进一步研 ...

  3. 第19部分- Linux x86 64位汇编GDB单步调试

    第19部分- Linux x86 64位汇编GDB单步调试 本篇我们使用gdb来调试上篇中的汇编代码. gdb调试 使用gdb进行调试. #gdb ./addsum_arg 设置参数: (gdb) s ...

  4. gdb 命令_gdb实用的调试技巧:启动方式、堆栈信息、单步调试

    对于很多开发者来说,开发过程中难免会遇到各种各样的bug, 所以,每个开发者应该考虑如何快速高效定位问题原因,而gdb是linux上很实用的调试工具,熟练掌握其调试技巧,将有助于提高解决问题的效率,也 ...

  5. 解决nasm汇编gdb无法单步调试

    我的环境:Ubuntu-desktop-20.04 LTS. 使用gdb调试nasm汇编时,无法单步调试,报错: Single stepping until exit from function _s ...

  6. linux下gdb单步调试

    用 GDB调试程序 GDB 概述 ---- GDB 是 GNU开源组织发布的一个强大的 UNIX下的程序调试工具.或许,各位比较喜欢那种图形界面方式的,像 VC. BCB等 IDE的调试,但如果你是在 ...

  7. GDB调试汇编堆栈过程分析

    GDB调试汇编堆栈过程分析 分析过程 .c代码文件 #include<stdio.h>short addend1 = 1;static int addend2 = 2;const stat ...

  8. GDB调试汇编堆栈过程的学习

    GDB调试汇编堆栈过程的学习 分析过程 这是我的C源文件: 1.安装32位兼容包 2.使用gcc - g example.c -o example -m32指令在64位的机器上产生32位汇编,然后使用 ...

  9. 20145223《信息安全系统设计基础》 GDB调试汇编堆栈过程分析

    20145223<信息安全系统设计基础> GDB调试汇编堆栈过程分析 分析的c语言源码 生成汇编代码--命令:gcc -g example.c -o example -m32 进入gdb调 ...

最新文章

  1. 文件服务器的内存要多少,文件服务器内存要多大
  2. Shell教程(五):替代、引用机制、输入输出重定向
  3. Maven环境配置及IntelliJ IDEA中的Maven部署(亲自测试)
  4. [20190805]在小程序中使用npm包
  5. PowerBI从Exchange跟踪日志中分析数据和KPI展现
  6. Ajax技术的一些总结
  7. 网络IPC:套接字之套接字描述符
  8. 在IIS上SSL的部署和启动SSL安全
  9. WinPmem:跨平台内存采集工具
  10. 近40年码龄,从通宵写代码到三思而后行——专访云风
  11. 基于微信小程序的毕业设计题目(35)PHP医院预约挂号小程序(含开题报告、任务书、中期报告、答辩PPT、论文模板)
  12. 盘点2018年化工行业大事故!回顾那些令人心痛的瞬间......
  13. 【Excel】给Excel生成工作表目录
  14. 手术麻醉信息管理系统源码,生成规范麻醉文书,自动信息采集
  15. 家装家居自救指南:线上线下大融合
  16. MySQL基础教程---创建、查询、备份数据库
  17. 利用iTerm2+oh-my-zsh+Dracula主题打造我的Mac终端利器
  18. dll名称相同引发的奇葩问题
  19. 故障处理 软件 需求_YamahaYamaha机器人RCX340控制器报警故障维护【AVG机器人系统】_智能云仓储库存wms管理分配货_电子标签价签拣货系统_工控erp上位机软件开发设计...
  20. 2021高考成绩查询数学和物理,2021高考难度趋势预测:2021高考难度会上升吗?高考数学题难不难?...

热门文章

  1. php元素浮动会产生哪些影响,css浮动带来什么问题
  2. php查看运行时间和内存,php 统计时间和内存的使用情况
  3. vasp和ms_科学网—VASP如何计算铁磁和考虑强关联作用 - 叶小球的博文
  4. 怎么更改Windows11鼠标指针大小和样式
  5. RTMP/RTSP推送端和RTMP/RTSP播放端录像设计探讨
  6. 方法区元空间实现之jdk7和8字符串常量池、运行时常量池、静态变量到底在哪?
  7. SpringAop与AspectJ的联系与区别____比较分析 Spring AOP 和 AspectJ 之间的差别
  8. Shiro——RememberMe
  9. linux第三方模块参数,nginx 的第三方模块ngx_http_accesskey_module 来实现下载文件的防盗链步骤(linux系统下)...
  10. linux内核多大 4.17.8,Linux Kernel 4.17结束支持,请升级到Linux 4.18内核