GDB调试技巧实战--为优化版release版本的函数寻找参数值

2023-05-16

在上一篇《GDB调试技巧实战–为release版本的函数寻找参数值》中,我们探讨了一种为函数找参数的办法,
但是,那是最理想的情况 -

  1. 编译时没有使用-fomit-frame-pointer。
  2. 编译时没有开启优化。

还是接着用上节的c代码,让我们详细看看call1函数在不同编译条件下的汇编代码。

  • 没使用-fomit-frame-pointer,没优化
    一切都很完美(rbp是栈基,rsp是占顶,使用edi/esi等寄存器传参,没用的变量也分配了空间):
gcc release_core_csdn.c
(gdb) disass call1
Dump of assembler code for function call1:
   0x00000000004007df <+0>:     push   %rbp
   0x00000000004007e0 <+1>:     mov    %rsp,%rbp
   0x00000000004007e3 <+4>:     sub    $0x20,%rsp
   0x00000000004007e7 <+8>:     mov    %edi,-0x14(%rbp)
   0x00000000004007ea <+11>:    mov    %esi,-0x18(%rbp)
   0x00000000004007ed <+14>:    movl   $0x6c6c6163,-0x10(%rbp)  //eye_catcher
   0x00000000004007f4 <+21>:    movw   $0x31,-0xc(%rbp)
   0x00000000004007fa <+27>:    mov    -0x18(%rbp),%edx
   0x00000000004007fd <+30>:    mov    -0x14(%rbp),%eax
   0x0000000000400800 <+33>:    mov    %eax,%esi
   0x0000000000400802 <+35>:    mov    $0x4009ae,%edi
   0x0000000000400807 <+40>:    mov    $0x0,%eax
   0x000000000040080c <+45>:    callq  0x4005c0 <printf@plt>
   0x0000000000400811 <+50>:    mov    $0x16,%esi
   0x0000000000400816 <+55>:    mov    $0x15,%edi
   0x000000000040081b <+60>:    callq  0x400799 <call2>
   0x0000000000400820 <+65>:    leaveq
   0x0000000000400821 <+66>:    retq

  • 仅仅使用编译选项-fomit-frame-pointer
    rbp不再是栈基(function prolog变了), 其它都正常。
gcc release_core_csdn.c  -fomit-frame-pointer
(gdb) disass call1
Dump of assembler code for function call1:
   0x00000000004007ee <+0>:     sub    $0x28,%rsp
   0x00000000004007f2 <+4>:     mov    %edi,0xc(%rsp)
   0x00000000004007f6 <+8>:     mov    %esi,0x8(%rsp)
   0x00000000004007fa <+12>:    movl   $0x6c6c6163,0x10(%rsp)
   0x0000000000400802 <+20>:    movw   $0x31,0x14(%rsp)
   0x0000000000400809 <+27>:    mov    0x8(%rsp),%edx
   0x000000000040080d <+31>:    mov    0xc(%rsp),%eax
   0x0000000000400811 <+35>:    mov    %eax,%esi
   0x0000000000400813 <+37>:    mov    $0x4009ce,%edi
   0x0000000000400818 <+42>:    mov    $0x0,%eax
   0x000000000040081d <+47>:    callq  0x4005c0 <printf@plt>
   0x0000000000400822 <+52>:    mov    $0x16,%esi
   0x0000000000400827 <+57>:    mov    $0x15,%edi
   0x000000000040082c <+62>:    callq  0x4007a1 <call2>
   0x0000000000400831 <+67>:    add    $0x28,%rsp
   0x0000000000400835 <+71>:    retq
  • 开启优化-O1, 一眼看上去指令少了很多,函数变短了;rbp也不用了;没用过得变量如eye_catcher被优化没了。
gcc release_core_csdn.c -O1
(gdb) disass call1
Dump of assembler code for function call1:
   0x000000000040074e <+0>:     sub    $0x8,%rsp
   0x0000000000400752 <+4>:     mov    %esi,%edx
   0x0000000000400754 <+6>:     mov    %edi,%esi
   0x0000000000400756 <+8>:     mov    $0x4008ce,%edi
   0x000000000040075b <+13>:    mov    $0x0,%eax
   0x0000000000400760 <+18>:    callq  0x400590 <printf@plt>
   0x0000000000400765 <+23>:    mov    $0x16,%esi
   0x000000000040076a <+28>:    mov    $0x15,%edi
   0x000000000040076f <+33>:    callq  0x400727 <call2>
   0x0000000000400774 <+38>:    add    $0x8,%rsp
   0x0000000000400778 <+42>:    retq
  • 开启优化-O2:除了O1优化项外,还把call2内联了进来,少了调用call2需要的额外成本。
$ gcc *csdn.c -O2
(gdb) disass call1
Dump of assembler code for function call1:
   0x00000000004007d0 <+0>:     sub    $0x8,%rsp
   0x00000000004007d4 <+4>:     mov    %esi,%edx
   0x00000000004007d6 <+6>:     xor    %eax,%eax
   0x00000000004007d8 <+8>:     mov    %edi,%esi
   0x00000000004007da <+10>:    mov    $0x4008ee,%edi
   0x00000000004007df <+15>:    callq  0x400590 <printf@plt>
   0x00000000004007e4 <+20>:    mov    $0x16,%edx
   0x00000000004007e9 <+25>:    mov    $0x15,%esi
   0x00000000004007ee <+30>:    mov    $0x4008d0,%edi
   0x00000000004007f3 <+35>:    xor    %eax,%eax
   0x00000000004007f5 <+37>:    callq  0x400590 <printf@plt> //call2
   0x00000000004007fa <+42>:    movl   $0x5,0x0
   0x0000000000400805 <+53>:    add    $0x8,%rsp
   0x0000000000400809 <+57>:    retq

一般用C/C++发布的包都是经过编译器优化的,这样的程序已经不能用rbp追踪每层的栈基了,只能从最后的rsp结合每个函数的汇编代码一层层的往上加offset(如sub $0x8,%rsp,offset就是8,还要注意额外的push/pop指令)找到每层的栈基。这是一个很痛苦的过程!

最佳实践:
细心的读者可能已经注意到每个函数中都有一个字符串eye_catcher, 如果它没被优化掉便可以通过查找内存的办法直接找到这个字符串,从而找到对应函数的栈。为了防止eye_cather被优化点,建议声明为:

volatile char eye_catcher[]="call1";

另外,建议每个数据结构的开头也放一个eye_catcher, 看到这个字符串从而一下就知道是某个数据结构。这样当你怀疑某个地址是某个参数时,特别是复杂数据结构的指针时,方便验证你的想法。

struct XXX{
	char eye_catcher[4];
	...
};

还有一个好处:通过观察eye_catcher,如果不是预期值,很有可能发生了内存overflow。内存问题可是占了C/C++程序总BUG数的70%。
会牺牲一点点performance, 但是值得!
最后简单看下O2条件下,崩溃时的栈,大致能看出从哪到哪是哪个函数的栈:

(gdb) where
#0  0x000000000040085d in call1 ()
#1  0x00000000004008a4 in call0 ()
#2  0x0000000000400629 in main ()
(gdb) x /64s $rsp
0x7fffffffe0b0: "call1"
0x7fffffffe0b6: ""
0x7fffffffe0b7: ""
0x7fffffffe0b8: "h\352\377\367\377\177"
0x7fffffffe0bf: ""
0x7fffffffe0c0: "call2"
0x7fffffffe0c6: ""
0x7fffffffe0c7: ""
0x7fffffffe0c8: "P\341\377\367\377\177"
0x7fffffffe0cf: ""
0x7fffffffe0d0: "\003"
0x7fffffffe0d2: ""
0x7fffffffe0d3: ""
0x7fffffffe0d4: ""
0x7fffffffe0d5: ""
0x7fffffffe0d6: ""
0x7fffffffe0d7: ""
0x7fffffffe0d8: "\244\b@"
0x7fffffffe0dc: ""
0x7fffffffe0dd: ""
0x7fffffffe0de: ""
0x7fffffffe0df: ""
0x7fffffffe0e0: "call0"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GDB调试技巧实战--为优化版release版本的函数寻找参数值 的相关文章

  • Android Bitmap防止内存溢出

    1 Bitmap 在Android开发中经常会使用到Bitmap xff0c 而Bitmap使用不当很容易引发OOM Bitmap占用内存大小的计算公式为 xff1a 图片宽度 图片高度 一个像素点所占字节数 xff0c 因此减小这三个参数
  • Swift NSAttributedString的使用

    NSMutableAttributedString let testAttributes 61 NSAttributedStringKey foregroundColor UIColor blue NSAttributedStringKey
  • Android ViewStub

    1 ViewStub ViewStub是一个可用于性能优化的控件 xff0c 它是一个不可见的 零尺寸的View xff0c 可以在运行时进行延迟加载一个布局文件 xff0c 从而提高显示速率 viewstub和include比较像 xff
  • Android Jetpack—LiveData和数据倒灌

    1 LiveData LiveData是Android Jetpack包提供的一种可观察的数据存储器类 xff0c 它可以通过添加观察者被其他组件观察其变更 不同于普通的观察者 xff0c LiveData最重要的特征是它具有生命周期感知能
  • Gradle build 报错:Received status code 400 from server: Bad Request

    全部错误是这样的 xff1a Could not GET 39 https dl google com dl android maven2 com android tools build gradle 3 1 2 gradle 3 1 2
  • 排列组合详解

    在笔试题中看到的一个选择题 用1 3的瓷砖密铺3 20的地板有几种方式 xff1f 排列组合问题 排列和组合问题 xff0c 其实是两种问题 xff0c 区分它们的原则是是否需要考虑顺序的不同 排列问题 xff0c 考虑顺序 xff1b 组
  • SCKKRS-关键词、关键短语提取

    1 简介 SCKKRS Self supervised Contextual Keyword and Keyphrase Retrieval with Self Labelling 本文根据2019年 Self supervised Con
  • kali安装vnc

    一 安装x11vnc 1 经过N多次的实验 xff0c kali一直报错 xff0c tightvncserver一直报错 怎么配置都是黑屏 xff0c 奔溃 最后退而求其次 xff0c 安装x11vnc 2 很简单的命令 sudo apt
  • 计算机硬件技术基础第一章总结

    1 1 计算机发展概述 1 1 1 计算机的发展简史 第一台计算机 xff1a ENIAC 第一代 xff1a 电子管数字计算机 xff08 1946 1958 xff09 逻辑元件 xff1a 真空电子管体积大 xff0c 功耗高 xff
  • CentOS7安装Oracle JDK1.8

    JDK1 8下载地址 https www oracle com java technologies javase javase8 archive downloads html 需要登录之后才能下载文件 xff0c 下载jdk 8u202 l
  • Ubuntu 16.04 安装 rtl8812au系列 (DWA-182) wireless adapter driver

    Ubuntu 16 04 安装 rtl8812au系列 DWA 182 wireless adapter driver 刚刚开始使用Linux xff0c 一脸懵逼 xff0c 命令行搞得一愣一愣的 xff0c 不过熟悉了之后就好很多了 一
  • SpringBoot项目启动失败报错Annotation-specified bean name ‘xx‘ for bean class [xxx] conflicts with existing

    问题描述 xff1a 项目启动就会报 xff1a Annotation specified bean name xx for bean class xxx conflicts with existing non compatible bea
  • Visual Studio高效实用的扩展工具、插件

    说明 xff1a 对一个有想法的程序员来说 xff0c 善于使用一款高效的开发工具是很重要的 xff0c 今天给大家介绍的是宇宙第一IDE vs用起来很不错的开发工具 xff0c 假如大家觉得不错也可以尝试的用用 xff0c 毕竟对于我们这
  • java琐事

    并发编程 并发的意义 并发通常是提高运行在单处理器上的程序的性能 如果程序中的某个任务因为该程序控制范围之外的某些条件 I O 而导致不能继续执行 xff0c 那么这个任务或线程就阻塞了 如果没有并发 xff0c 整个程序都讲停下来 从性能
  • java类的初始化和实例化的初始化(类的初始化过程)

    Java类的加载顺序 父类静态代变量 父类静态代码块 子类静态变量 子类静态代码块 父类非静态变量 xff08 父类实例成员变量 xff09 父类构造函数 子类非静态变量 xff08 子类实例成员变量 xff09 子类构造函数 上面的说法也
  • 最优吞吐量和最短停顿时间

    在实践活动中 xff0c 我们通过最优吞吐量和最短停顿时间来评价jvm系统的性能 吞吐量越高算法越好 暂停时间越短算法越好 首先让我们来明确垃圾收集 GC 中的两个术语 吞吐量 throughput 和暂停时间 pause times JV
  • sql执行慢的原因有哪些,如何进行sql优化?

    一 导致SQL执行慢的原因 1 硬件问题 如网络速度慢 xff0c 内存不足 xff0c I O吞吐量小 xff0c 磁盘空间满了等 2 没有索引或者索引失效 xff08 一般在互联网公司 xff0c DBA会在半夜把表锁了 xff0c 重
  • 阿里java开发手册2019年最新版619(华山版)PDF下载

    链接 https pan baidu com s 1ANvBu1hidnvRCZILDGXuQA 密码 ugq8
  • Mockito:org.mockito.exceptions.misusing.InvalidUseOfMatchersException

    org span class token punctuation span mockito span class token punctuation span exceptions span class token punctuation
  • 一个简单通用的基于java反射实现pojo转为fastjson对象的方法

    最近在公司工作需要实现一个工具实现一个pojo转为fastjson对象的通用工具 xff0c 直接上源码 span class token comment 通用的pojo转为Json对象的方法 64 author ZFX 64 date20

随机推荐

  • Java魔法类:Unsafe应用解析

    这个美团大神对于Unsafe的分析很全面 https tech meituan com 2019 02 14 talk about java magic class unsafe html
  • Linux X-Window Error: Can‘t open display: :0

    问题过程描述 许多经常部署Oracle数据的管理员经常需要对数据库软件进行部署 xff0c 但大多数都是通过远程部署的方式进行部署 xff0c 使用远程部署有两种方式 xff0c 一种是通过脚本部署 xff0c 另一种就是通过图形化进行部署
  • maven打包生成war跳过单元测试

    maven将项目打包成war包的命令是 mvn install 或mvn package 每次生成war包时会进行所以的单元测试 xff0c 如果想跳过单元测试直接生成war包有以下3种方式 方法1 xff1a 在pom xml中加入如下代
  • 程序员每天工作多少个小时_程序员每天实际工作几个小时?

    程序员每天工作多少个小时 您如何看待 xff0c 程序员每天实际工作多长时间 xff1f 大多数人会说答案是8到9个小时 有人说他们每天工作12个小时或更长时间 尽管这是正确的 xff0c 但它并不是大多数程序员实际工作的数量 xff0c
  • ubuntu 显示缺少库文件 libcom_err.so.2 解决办法

    运行任何代码都显示 xff1a error while loading shared libraries libcom err so 2 cannot open shared object file No such file or dire
  • 记CVTE第一次面试

    首先说明一下博主是一个大三的学生 xff0c 专业计算机科学与技术 xff0c 主学的方向是Web后台开发 xff0c 主语言是Java 前几天看到CVTE有校园招聘实习生 xff0c 就报名参加了 xff0c 做了CVTE的笔试题 xff
  • Java Socket 编程那些事(1)

    前言 最近在准备面试和笔试的一些东西 xff0c 回去翻看了Java关于IO的基础 xff0c 发现很多基础还是没有记牢固 xff0c 现在回头重新学习 xff0c 就从socket通讯开始吧 xff0c 虽然说现在企业很少直接编写sock
  • Redis集群的原理和搭建

    前言 Redis 是我们目前大规模使用的缓存中间件 xff0c 由于它强大高效而又便捷的功能 xff0c 得到了广泛的使用 单节点的Redis已经就达到了很高的性能 xff0c 为了提高可用性我们可以使用Redis集群 本文参考了Rdis的
  • Java多线程爬虫爬取京东商品信息

    前言 网络爬虫 xff0c 是一种按照一定的规则 xff0c 自动地抓取万维网信息的程序或者脚本 爬虫可以通过模拟浏览器访问网页 xff0c 从而获取数据 xff0c 一般网页里会有很多个URL 爬虫可以访问这些URL到达其他网页 xff0
  • 关于js中的“Uncaught SyntaxError: Unexpected token

    我在js中为一个已经定义的数组重新定义新的一个维度的数组时 xff0c 调试器这样报错 只说结果 xff1a 肯定是在给已经定义的数组中的元素重新定义下一维度时 xff0c 多在前面加了一个 var 就像下面的这样 xff1a var gr
  • 学成在线--day03 CMS页面管理开发

    学成在线 第3天 讲义 CMS页面管理开发 1 自定义条件 1 1 需求分析 在页面输入查询条件 xff0c 查询符合条件的页面信息 查询条件如下 xff1a 站点Id xff1a 精确匹配 模板Id xff1a 精确匹配 页面别名 xff
  • Ubuntu下安装Inode后双击InodeClient无反映解决方法

    由于比较喜好linux编程环境 xff0c 所以准本一直使用linux 学校无线有时有有时没很不爽 xff0c 所以准本安装Inode xff0c 但是安装完Inode后双击是一直没反映 最后求助万能的百度 xff0c 谁知道百度的搜索不得
  • 使用GitHub托管网站,自定义域名

    1 如何使用GitHub托管 官网链接 xff1a 点击跳转 官网首页就有详细的搭建步骤 xff0c 总共5步便可搭建成功 访问 github用户名 github io 便可看到自己的网站 2 自定义域名的方法 1 申请一个域名 xff0c
  • ElasticsearchRestTemplate 基本使用

    随着数据量的增加和数据结构的复杂化 xff0c 传统的关系型数据库已经不能满足用户的需求 xff0c 而搜索引擎则成为了一种更加高效 可扩展的数据检索方案 而 Elasticsearch 则是一个流行的搜索引擎 xff0c 在 Java 生
  • Navcat无法连接mysql报错1449

    把mysql从5升级成8后第二次连接mysql就报错1449 不清楚什么原因 xff0c 反正肯定是升级数据库之后mysql用户被动了 xff0c 看了很多博客都没有用 xff0c 什么在navcat里新建用户 xff0c 数据库都连不上怎
  • Kafka —— java实现一生产者多消费者实例

    架构图 xff1a xff08 网图 xff0c 很通俗易懂了 xff0c 就不自己画了 xff0c 这里实现的是一个Producer 两个Consumer xff09 前提 xff1a 已经开启zookeeper 和kafka xff0c
  • 程序员玩游戏之三--天天爱消除非暴力脚本

    评论 xff1a 此款游戏成功在其好友排名上 好友的分数超过了你无疑会增加你的斗志 中级策略 xff1a 七手八脚多人一起点 这相当于多个CPU处理一个大任务了 xff0c 哈哈 终极策略 xff1a 自动化 机器总是比人快的多 你两个人一
  • 程序员玩游戏之四--娱网棋牌大连打滚子记牌器

    话说大连人都爱打滚子 xff0c 所以本人就做了一个打滚子记牌器 基本原理同 程序员玩游戏之一 自动对对碰 xff0c 故此处不再赘述 xff0c 只留下一张截图吧 代码请见资源地址 xff1a http download csdn net
  • 为SIGSEGV设置handler有用吗?

    背景 最近几天看到先辈们30年前留下了一块代码 xff0c 为SIGSEGV设置了handler xff0c 所以心中有了两个疑问 xff1a 为SIGSEGV设置handler有没有用 xff1f 能否跳过引起崩溃的那一句指令 xff1f
  • GDB调试技巧实战--为优化版release版本的函数寻找参数值

    在上一篇 GDB调试技巧实战 为release版本的函数寻找参数值 中 xff0c 我们探讨了一种为函数找参数的办法 xff0c 但是 xff0c 那是最理想的情况 编译时没有使用 fomit frame pointer 编译时没有开启优化