<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>GDB on 夜云泊</title>
    <link>https://lifeislife.cn/tags/gdb/</link>
    <description>feedId:57980998056508425+userId:73222296380546048 Recent content in GDB on 夜云泊</description>
    <generator>Hugo -- 0.160.1</generator>
    <language>zh</language>
    <lastBuildDate>Sun, 14 Aug 2022 14:17:26 +0000</lastBuildDate>
    <atom:link href="https://lifeislife.cn/tags/gdb/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>DEBUG 原理</title>
      <link>https://lifeislife.cn/posts/debug%E5%8E%9F%E7%90%86/</link>
      <pubDate>Sun, 14 Aug 2022 14:17:26 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/debug%E5%8E%9F%E7%90%86/</guid>
      <description>&lt;p&gt;了解调试原理时看到了一个质量比较高的视频，&lt;a href=&#34;https://www.bilibili.com/video/BV1iN411Z7jk?spm_id_from=333.999.0.0&amp;amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44&#34;&gt;【蛋饼嵌入式】一起探究调试原理&lt;/a&gt;。UP 通俗，形象地讲解了 DEBUG 的一些原理，值得反复观看，但是视频不如文字查阅效率高，遂记录了以下文稿内容。&lt;/p&gt;
&lt;h2 id=&#34;什么是-jtag&#34;&gt;什么是 JTAG&lt;/h2&gt;
&lt;p&gt;1985 年，几家半导体厂商为了解决板级测试的问题，成立了 Joint Test Action Group（JTAG）联合测试行动小组，他们希望将测试点和测试电路集成在芯片内部引脚处。同时，留出一个统一协议的接口，大家都能通过这个接口来访问芯片的输入与输出状态。这样就省去了板级测试是的物理接触，同时还能进行逻辑性调试。后来 IEEE 组织，将这个方案制定成了标准 IEEE 1149.1，这就是现在我们常听到的 JTAG 调试。&lt;/p&gt;
&lt;h2 id=&#34;边界扫描技术&#34;&gt;边界扫描技术&lt;/h2&gt;
&lt;p&gt;实现 JTAG 调试最重要的一个技术就是边界扫描技术，核心思想是&lt;strong&gt;给芯片的每一个输入输出引脚，添加一个移位寄存器单元，也称为边界扫描单元&lt;/strong&gt;（Boundary Scan Cell，BSC）。通过它一边可以实现对芯片输出数据的截取，另一边可以完成对输入数据的替代。正常运行状态下，这些寄存器又是透明般的存在。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141648874.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141648874.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;这些位于引脚边界的移位寄存器，还可以串在一起，形成一条边界扫描链，以串行的方式从外部更新扫描单元上的数据，以及对外输出边界扫描单元捕获的数据。如果板上有多个这样的芯片，他们还能以菊花链的形式串联在一起，这样就大大方便了测试的过程。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141654770.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141654770.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;要实现对内部移位寄存器单元或者说对整个扫描链的访问和操作，便依赖于 JTAG 调试协议和相应的物理接口。JTAG 标准接口包括以下几个部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TDI(Test Data In)&lt;/li&gt;
&lt;li&gt;TDO(Test Data Out)&lt;/li&gt;
&lt;li&gt;TCLK(Test Clock)&lt;/li&gt;
&lt;li&gt;TMS(Test Mode Select)&lt;/li&gt;
&lt;li&gt;TRST(Test Reset)：可选，用于复位&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141655524.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141655524.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;调试逻辑的实现，是通过芯片内部的 TAP（Test Access Port）来完成的。模式状态信号 TMS 配合测试时钟信号 TCLK，以一定的时序进入到 TAP 控制器后，由 TAP 控制器内部的状态机转化为相应的控制动作。从而完成数据的移位，引脚状态的捕获和更新。&lt;/p&gt;
&lt;p&gt;设备 ID 寄存器构成的扫描链，板卡一连上调试器，通过对这条扫描链的访问，就能够识别到被调试芯片的信号。存放调试机制相关配置的数据寄存器，所构成的扫描链，后面断点和单步调试时就会用到。以及移位的 BYPASS 寄存器，当调试链路上有多个芯片连接时，来减少总调试链路的长度。&lt;/p&gt;
&lt;p&gt;以上都属于数据寄存器构成扫描链，因为想要在他们之间进行切换，需要引入另外的指令寄存器，以及对应的扫描链，这样调试主机将不同的调试命令写到指令寄存器中，就可以选通需要调试的数据链路。数据与指令寄存器两种链路的切换，就通过 TAP 控制器完成。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;补充：
如果芯片支持 JTAG 调试，那么芯片上就必须有上述的四个接口，TDI，TDO，TCLK，TMS。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141725205.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141725205.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
芯片外有个 Adapter 与之 Pin to Pin 连接，负责协议转换，把 USB 的 JTAG 控制信息按 JTAG 协议转换输出，满足协议定义的电气特性。
Adapter 与 Host 连接，Host 可以是我们的 PC，也可以是另一个嵌入式调试器。
Host 上通常需要运行一些软件，如 OpenOCD，负责把 GDB 的高级别命令转换成 JTAG 命令，并通过特定 Adapter 的要求进行打包，调用 OS 提供的 USB/ETH/PCI 驱动发送出去。
GDB 与 OpenOCD 通过一些远程协议，如 TCP/IP，进行通信。这样就能够调试 Chip。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;断点是如何实现的&#34;&gt;断点是如何实现的？&lt;/h2&gt;
&lt;p&gt;通过以上 JTAG 调试接口，我们已经能够测试引脚的输入输出了，同时也获得了观察和改变芯片内部数据的机会，那么接下来我们如何进行调试呢？比如打个断点？&lt;/p&gt;
&lt;p&gt;断点作为一种干预性调试，根据调试行为的不同，分为监控模式和中止模式。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;监控模式（软件断点）：会触发异常，交由相应的软件程序来处理，处理器仍然处于运行状态。&lt;/li&gt;
&lt;li&gt;中止模式（硬件断点），使处理器进入非正常运行的调试状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以 ARM 架构来说，最初工程师想到的办法是插入一条指令集中没有定义的无效指令，来&lt;strong&gt;替换掉希望打断指令处的源指令&lt;/strong&gt;。这样内核运行到这条指令时，就会进入到无效指令的服务程序，在这个异常的服务程序中，我们再去做想要的调试操作，操作完成后，还原当时被替换的指令。并继续执行。&lt;/p&gt;
&lt;p&gt;后来 ARMv5 开始引入专门用于调试的&lt;code&gt;BKPT&lt;/code&gt;指令，类似与 X86 指令集的&lt;code&gt;INT3&lt;/code&gt;指令，但不管是不是专用指令，他们都属于软件中断。这意味着我想要实时地添加这种断点，就要求能够随时地更改程序，插入断点指令，而一般只有程序运行在 RAM 上，才方便这样操作。那如果直接从 FLASH 上取址运行的程序，因为 FLASH 先擦后写的物理特性，是无法通过随意插入指令来实现断点的。更不要说从只读存储器上运行的程序，比如说固化在 BIOS 中上电自检 POST 程序，面对这种情况，需要的就是硬件断点。&lt;/p&gt;
&lt;p&gt;硬件断点顾名思义，需要额外的硬件逻辑支持，主要起的作用就是&lt;strong&gt;暂存和比较&lt;/strong&gt;，我们把这种实现特定逻辑的组合电路，称为&lt;strong&gt;宏单元&lt;/strong&gt;（Macro Cell）。&lt;/p&gt;
&lt;p&gt;还记得我们前面说过 JTAG 协议，支持自定义扩展扫描链吗？硬件断点宏单元的控制和比较两种数据寄存器，就可以作为两条拓展扫描链，加入到 JTAG 调试框架中。&lt;/p&gt;
&lt;p&gt;你在调试软件中按下一个按钮，对应的那行代码地址，就会通过上述扫描链，被记录到断点宏单元相应的寄存器中，当然，调试器能够知道某行代码的地址，是依赖于编译时生成的 ELF 文件中的符号表信息。而当程序正常运行取址时，如果宏单元的寄存器，发现了总线上出现了记录过的地址，比较器就会发出调试状态信号，CPU 接收到这个信号后暂停运行，进入调试模式或者异常。&lt;/p&gt;
&lt;p&gt;因为每打一个断点，都需要宏单元相应的寄存器来保存地址信息。而寄存器数量是有限的，所以调试软件一旦和芯片建立起了连接，就会通过上述的另外一条控制寄存器获得该硬件断点宏单元所支持的最大断点数，这样你在调试过程中如果断点打多了，调试器就会报错。&lt;/p&gt;
&lt;h2 id=&#34;为什么调试器能够烧录程序呢&#34;&gt;为什么调试器能够烧录程序呢？&lt;/h2&gt;
&lt;p&gt;正常情况下，CPU 内核通过内部的系统总线，从 FLASH 或者 RAM 中获取运行的指令，交换数据，并在一定的驱动程序下，实现对 FLASH 的擦除和写入操作。为了把指令和数据直接给 CPU 内核，我们还需要定义一条扫描链，这条扫描链直接在系统总线上开了一个口子，通过上位机的调试信号，把相关的操作指令直接传到总线上，供 CPU 内核取用。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141752418.gif&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141752418.gif&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;那么整个调试器的下载过程是这样的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第一，通过调试器使得 CPU 进入调试模式；&lt;/li&gt;
&lt;li&gt;第二，通过总线扫描链将 FLASH 编程算法与即将被下载的用户程序放到 RAM 中；&lt;/li&gt;
&lt;li&gt;第三，将 CPU 的 PC 指针指向刚刚搬运完成的 RAM 地址起始处，并退出调试状态；&lt;/li&gt;
&lt;li&gt;第四，CPU 将在正常状态下运行 RAM 中的 FLASH 编程算法。将用户代码烧录到确定位置上，执行完成后回到调试状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果 RAM 空间不够大，以上操作还需要重复多次执行。&lt;/p&gt;
&lt;p&gt;需要注意的是，在第二步操作 RAM 时，是处于调试状态下，而调试时钟的速率是无法满足 RAM 或者 FLASH 的访问速率要求的，所以在这一过程中，CPU 会频繁的在系统时钟与调试时钟之间切换&lt;/p&gt;
&lt;p&gt;调试时钟下，总线扫描链先传递来要写入的数据和 RAM 地址，CPU 先分别暂存在内部通用寄存器中，接着扫描链传递写入指令，并切换为系统时钟。CPU 在正常状态下执行搬运指令，往 RAM 里写入数据，执行完成后回到调试状态，继续通过扫描链传递后面要写入的值，&lt;/p&gt;
&lt;h2 id=&#34;openocd-open-on-chip-debugger&#34;&gt;OpenOCD (Open On-Chip Debugger)&lt;/h2&gt;
&lt;p&gt;OpenOCD（Open On-Chip Debugger）开源片上调试器，是一款开源软件，最初是由 Dominic Rath 同学还在大学期间发起的（2005 年）项目。OpenOCD 旨在提供针对嵌入式设备的调试、系统编程和边界扫描功能。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://www.bilibili.com/video/BV1iN411Z7jk?spm_id_from=333.999.0.0&amp;amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44&#34;&gt;【蛋饼嵌入式】饮茶先？DEBUG 先！一起探究调试原理_哔哩哔哩_bilibili&lt;/a&gt;
&lt;a href=&#34;https://zhuanlan.zhihu.com/p/125145986&#34;&gt;浅谈 RISC-V 的 DEBUG 系统及其仿真 - 知乎&lt;/a&gt;
&lt;a href=&#34;https://www.bilibili.com/video/BV1s54y1Z7Zj/?spm_id_from=333.788&amp;amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44&#34;&gt;ESP32 JTAG Debug 01: JTAG 接口简介_哔哩哔哩_bilibili&lt;/a&gt;+&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<p>了解调试原理时看到了一个质量比较高的视频，<a href="https://www.bilibili.com/video/BV1iN411Z7jk?spm_id_from=333.999.0.0&amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44">【蛋饼嵌入式】一起探究调试原理</a>。UP 通俗，形象地讲解了 DEBUG 的一些原理，值得反复观看，但是视频不如文字查阅效率高，遂记录了以下文稿内容。</p>
<h2 id="什么是-jtag">什么是 JTAG</h2>
<p>1985 年，几家半导体厂商为了解决板级测试的问题，成立了 Joint Test Action Group（JTAG）联合测试行动小组，他们希望将测试点和测试电路集成在芯片内部引脚处。同时，留出一个统一协议的接口，大家都能通过这个接口来访问芯片的输入与输出状态。这样就省去了板级测试是的物理接触，同时还能进行逻辑性调试。后来 IEEE 组织，将这个方案制定成了标准 IEEE 1149.1，这就是现在我们常听到的 JTAG 调试。</p>
<h2 id="边界扫描技术">边界扫描技术</h2>
<p>实现 JTAG 调试最重要的一个技术就是边界扫描技术，核心思想是<strong>给芯片的每一个输入输出引脚，添加一个移位寄存器单元，也称为边界扫描单元</strong>（Boundary Scan Cell，BSC）。通过它一边可以实现对芯片输出数据的截取，另一边可以完成对输入数据的替代。正常运行状态下，这些寄存器又是透明般的存在。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141648874.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141648874.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>这些位于引脚边界的移位寄存器，还可以串在一起，形成一条边界扫描链，以串行的方式从外部更新扫描单元上的数据，以及对外输出边界扫描单元捕获的数据。如果板上有多个这样的芯片，他们还能以菊花链的形式串联在一起，这样就大大方便了测试的过程。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141654770.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141654770.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>要实现对内部移位寄存器单元或者说对整个扫描链的访问和操作，便依赖于 JTAG 调试协议和相应的物理接口。JTAG 标准接口包括以下几个部分：</p>
<ul>
<li>TDI(Test Data In)</li>
<li>TDO(Test Data Out)</li>
<li>TCLK(Test Clock)</li>
<li>TMS(Test Mode Select)</li>
<li>TRST(Test Reset)：可选，用于复位</li>
</ul>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141655524.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141655524.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>调试逻辑的实现，是通过芯片内部的 TAP（Test Access Port）来完成的。模式状态信号 TMS 配合测试时钟信号 TCLK，以一定的时序进入到 TAP 控制器后，由 TAP 控制器内部的状态机转化为相应的控制动作。从而完成数据的移位，引脚状态的捕获和更新。</p>
<p>设备 ID 寄存器构成的扫描链，板卡一连上调试器，通过对这条扫描链的访问，就能够识别到被调试芯片的信号。存放调试机制相关配置的数据寄存器，所构成的扫描链，后面断点和单步调试时就会用到。以及移位的 BYPASS 寄存器，当调试链路上有多个芯片连接时，来减少总调试链路的长度。</p>
<p>以上都属于数据寄存器构成扫描链，因为想要在他们之间进行切换，需要引入另外的指令寄存器，以及对应的扫描链，这样调试主机将不同的调试命令写到指令寄存器中，就可以选通需要调试的数据链路。数据与指令寄存器两种链路的切换，就通过 TAP 控制器完成。</p>
<blockquote>
<p>补充：
如果芯片支持 JTAG 调试，那么芯片上就必须有上述的四个接口，TDI，TDO，TCLK，TMS。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141725205.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141725205.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html>
芯片外有个 Adapter 与之 Pin to Pin 连接，负责协议转换，把 USB 的 JTAG 控制信息按 JTAG 协议转换输出，满足协议定义的电气特性。
Adapter 与 Host 连接，Host 可以是我们的 PC，也可以是另一个嵌入式调试器。
Host 上通常需要运行一些软件，如 OpenOCD，负责把 GDB 的高级别命令转换成 JTAG 命令，并通过特定 Adapter 的要求进行打包，调用 OS 提供的 USB/ETH/PCI 驱动发送出去。
GDB 与 OpenOCD 通过一些远程协议，如 TCP/IP，进行通信。这样就能够调试 Chip。</p>
</blockquote>
<h2 id="断点是如何实现的">断点是如何实现的？</h2>
<p>通过以上 JTAG 调试接口，我们已经能够测试引脚的输入输出了，同时也获得了观察和改变芯片内部数据的机会，那么接下来我们如何进行调试呢？比如打个断点？</p>
<p>断点作为一种干预性调试，根据调试行为的不同，分为监控模式和中止模式。</p>
<ul>
<li>监控模式（软件断点）：会触发异常，交由相应的软件程序来处理，处理器仍然处于运行状态。</li>
<li>中止模式（硬件断点），使处理器进入非正常运行的调试状态。</li>
</ul>
<p>以 ARM 架构来说，最初工程师想到的办法是插入一条指令集中没有定义的无效指令，来<strong>替换掉希望打断指令处的源指令</strong>。这样内核运行到这条指令时，就会进入到无效指令的服务程序，在这个异常的服务程序中，我们再去做想要的调试操作，操作完成后，还原当时被替换的指令。并继续执行。</p>
<p>后来 ARMv5 开始引入专门用于调试的<code>BKPT</code>指令，类似与 X86 指令集的<code>INT3</code>指令，但不管是不是专用指令，他们都属于软件中断。这意味着我想要实时地添加这种断点，就要求能够随时地更改程序，插入断点指令，而一般只有程序运行在 RAM 上，才方便这样操作。那如果直接从 FLASH 上取址运行的程序，因为 FLASH 先擦后写的物理特性，是无法通过随意插入指令来实现断点的。更不要说从只读存储器上运行的程序，比如说固化在 BIOS 中上电自检 POST 程序，面对这种情况，需要的就是硬件断点。</p>
<p>硬件断点顾名思义，需要额外的硬件逻辑支持，主要起的作用就是<strong>暂存和比较</strong>，我们把这种实现特定逻辑的组合电路，称为<strong>宏单元</strong>（Macro Cell）。</p>
<p>还记得我们前面说过 JTAG 协议，支持自定义扩展扫描链吗？硬件断点宏单元的控制和比较两种数据寄存器，就可以作为两条拓展扫描链，加入到 JTAG 调试框架中。</p>
<p>你在调试软件中按下一个按钮，对应的那行代码地址，就会通过上述扫描链，被记录到断点宏单元相应的寄存器中，当然，调试器能够知道某行代码的地址，是依赖于编译时生成的 ELF 文件中的符号表信息。而当程序正常运行取址时，如果宏单元的寄存器，发现了总线上出现了记录过的地址，比较器就会发出调试状态信号，CPU 接收到这个信号后暂停运行，进入调试模式或者异常。</p>
<p>因为每打一个断点，都需要宏单元相应的寄存器来保存地址信息。而寄存器数量是有限的，所以调试软件一旦和芯片建立起了连接，就会通过上述的另外一条控制寄存器获得该硬件断点宏单元所支持的最大断点数，这样你在调试过程中如果断点打多了，调试器就会报错。</p>
<h2 id="为什么调试器能够烧录程序呢">为什么调试器能够烧录程序呢？</h2>
<p>正常情况下，CPU 内核通过内部的系统总线，从 FLASH 或者 RAM 中获取运行的指令，交换数据，并在一定的驱动程序下，实现对 FLASH 的擦除和写入操作。为了把指令和数据直接给 CPU 内核，我们还需要定义一条扫描链，这条扫描链直接在系统总线上开了一个口子，通过上位机的调试信号，把相关的操作指令直接传到总线上，供 CPU 内核取用。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141752418.gif">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/202208141752418.gif" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>那么整个调试器的下载过程是这样的：</p>
<ul>
<li>第一，通过调试器使得 CPU 进入调试模式；</li>
<li>第二，通过总线扫描链将 FLASH 编程算法与即将被下载的用户程序放到 RAM 中；</li>
<li>第三，将 CPU 的 PC 指针指向刚刚搬运完成的 RAM 地址起始处，并退出调试状态；</li>
<li>第四，CPU 将在正常状态下运行 RAM 中的 FLASH 编程算法。将用户代码烧录到确定位置上，执行完成后回到调试状态。</li>
</ul>
<p>如果 RAM 空间不够大，以上操作还需要重复多次执行。</p>
<p>需要注意的是，在第二步操作 RAM 时，是处于调试状态下，而调试时钟的速率是无法满足 RAM 或者 FLASH 的访问速率要求的，所以在这一过程中，CPU 会频繁的在系统时钟与调试时钟之间切换</p>
<p>调试时钟下，总线扫描链先传递来要写入的数据和 RAM 地址，CPU 先分别暂存在内部通用寄存器中，接着扫描链传递写入指令，并切换为系统时钟。CPU 在正常状态下执行搬运指令，往 RAM 里写入数据，执行完成后回到调试状态，继续通过扫描链传递后面要写入的值，</p>
<h2 id="openocd-open-on-chip-debugger">OpenOCD (Open On-Chip Debugger)</h2>
<p>OpenOCD（Open On-Chip Debugger）开源片上调试器，是一款开源软件，最初是由 Dominic Rath 同学还在大学期间发起的（2005 年）项目。OpenOCD 旨在提供针对嵌入式设备的调试、系统编程和边界扫描功能。</p>
<h2 id="参考资料">参考资料</h2>
<p><a href="https://www.bilibili.com/video/BV1iN411Z7jk?spm_id_from=333.999.0.0&amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44">【蛋饼嵌入式】饮茶先？DEBUG 先！一起探究调试原理_哔哩哔哩_bilibili</a>
<a href="https://zhuanlan.zhihu.com/p/125145986">浅谈 RISC-V 的 DEBUG 系统及其仿真 - 知乎</a>
<a href="https://www.bilibili.com/video/BV1s54y1Z7Zj/?spm_id_from=333.788&amp;vd_source=7ff88341de4b5111bdf3db48b4e9ca44">ESP32 JTAG Debug 01: JTAG 接口简介_哔哩哔哩_bilibili</a>+</p>
]]></content:encoded>
    </item>
    <item>
      <title>CSAPPLAB-Bomb Lab</title>
      <link>https://lifeislife.cn/posts/csapp-lab-bomb-lab/</link>
      <pubDate>Sun, 29 Aug 2021 18:40:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/csapp-lab-bomb-lab/</guid>
      <description>&lt;h2 id=&#34;tips&#34;&gt;Tips&lt;/h2&gt;
&lt;h3 id=&#34;缩写注释&#34;&gt;缩写注释&lt;/h3&gt;
&lt;p&gt;CSAPP：Computer Systems A Programmer’s Perspective（深入理解计算机操作系统）。CSAPP（C：P166，O：P278）表示书本的中文版第 166 页，英文原版第 278 页。&lt;/p&gt;
&lt;h3 id=&#34;寄存器信息&#34;&gt;寄存器信息&lt;/h3&gt;
&lt;p&gt;了解寄存器的基本用途，看到一个汇编代码，可以大概了解这个寄存器是在栈中使用的，还是保存参数的，是调用者保存，还是被调用者保存。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;div STYLE=&#34;page-break-after: always;&#34;&gt;&lt;/div&gt;
&lt;h3 id=&#34;gdb&#34;&gt;GDB&lt;/h3&gt;
&lt;p&gt;调试过程用到的 GDB 命令可以先参考&lt;a href=&#34;https://dunky-z.github.io/2021/08/29/GDB%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/&#34;&gt;GDB 调试入门&lt;/a&gt;这篇文章。文中所用例子也是摘自与 BombLab 的源码，更容易理解如何使用。还有一定比较重要的是，如何使用 gdb 带参数调试。为了不用每次运行&lt;code&gt;bomb&lt;/code&gt;程序都需要重新输入答案，&lt;code&gt;bomb&lt;/code&gt;程序可以读取文本信息，在文本文件中写入答案即可免去手动输入。&lt;/p&gt;
&lt;h2 id=&#34;phase_1&#34;&gt;phase_1&lt;/h2&gt;
&lt;p&gt;拆弹专家已上线，开干！！！！！！！！！！！！！&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) b phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) b explode_bomb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function phase_1:&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ee0 &amp;lt;+0&amp;gt;: sub    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ee4 &amp;lt;+4&amp;gt;: mov    $0x402400,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ee9 &amp;lt;+9&amp;gt;: callq  0x401338 &amp;lt;strings_not_equal&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400eee &amp;lt;+14&amp;gt;: test   %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ef0 &amp;lt;+16&amp;gt;: je     0x400ef7 &amp;lt;phase_1+23&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ef2 &amp;lt;+18&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ef7 &amp;lt;+23&amp;gt;: add    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efb &amp;lt;+27&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3：将栈指针&lt;code&gt;rsp&lt;/code&gt;减去 8 个字节，也就是申请 8 个字节的栈空间&lt;/li&gt;
&lt;li&gt;4：将一个立即数存到寄存器&lt;code&gt;esi&lt;/code&gt;中&lt;/li&gt;
&lt;li&gt;5：调用函数&lt;code&gt;strings_not_equal&lt;/code&gt;，该函数第一条语句的地址为&lt;code&gt;0x401338&lt;/code&gt;。&lt;code&gt;callq&lt;/code&gt;指令的执行过程可参考书本 CSAPP（C：P166，O：P278）&lt;/li&gt;
&lt;li&gt;6：使用&lt;code&gt;test&lt;/code&gt;命令（同&lt;code&gt;and&lt;/code&gt;命令，不修改目标对象的值）来测试&lt;code&gt;eax&lt;/code&gt;中的值是否为&lt;code&gt;0&lt;/code&gt;，如果为&lt;code&gt;0&lt;/code&gt;则跳过引爆炸弹的函数&lt;/li&gt;
&lt;li&gt;7：这一句和上一句是一个整体，如果&lt;code&gt;eax==0&lt;/code&gt;,就跳转到&lt;code&gt;0x400ef7&lt;/code&gt;，这个地址也就是第 9 行的地址，成功跳过了引爆炸弹函数。意思就是我们输入的某个字符串成功匹配，也就是&lt;code&gt;strings_not_equal&lt;/code&gt;函数返回值为 0。&lt;/li&gt;
&lt;li&gt;8：调用函数&lt;code&gt;explode_bomb&lt;/code&gt;，引爆炸弹&lt;/li&gt;
&lt;li&gt;9：将栈指针&lt;code&gt;rsp&lt;/code&gt;加上 8 个字节，也就是恢复 8 个字节的栈空间&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas strings_not_equal 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function strings_not_equal:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;=&amp;gt; 0x0000000000401338 &amp;lt;+0&amp;gt;: push   %r12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133a &amp;lt;+2&amp;gt;: push   %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133b &amp;lt;+3&amp;gt;: push   %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133c &amp;lt;+4&amp;gt;: mov    %rdi,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040133f &amp;lt;+7&amp;gt;: mov    %rsi,%rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401342 &amp;lt;+10&amp;gt;: callq  0x40131b &amp;lt;string_length&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401347 &amp;lt;+15&amp;gt;: mov    %eax,%r12d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040134a &amp;lt;+18&amp;gt;: mov    %rbp,%rdi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040134d &amp;lt;+21&amp;gt;: callq  0x40131b &amp;lt;string_length&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401352 &amp;lt;+26&amp;gt;: mov    $0x1,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401357 &amp;lt;+31&amp;gt;: cmp    %eax,%r12d
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040135a &amp;lt;+34&amp;gt;: jne    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040135c &amp;lt;+36&amp;gt;: movzbl (%rbx),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040135f &amp;lt;+39&amp;gt;: test   %al,%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401361 &amp;lt;+41&amp;gt;: je     0x401388 &amp;lt;strings_not_equal+80&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401363 &amp;lt;+43&amp;gt;: cmp    0x0(%rbp),%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401366 &amp;lt;+46&amp;gt;: je     0x401372 &amp;lt;strings_not_equal+58&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401368 &amp;lt;+48&amp;gt;: jmp    0x40138f &amp;lt;strings_not_equal+87&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040136a &amp;lt;+50&amp;gt;: cmp    0x0(%rbp),%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040136d &amp;lt;+53&amp;gt;: nopl   (%rax)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401370 &amp;lt;+56&amp;gt;: jne    0x401396 &amp;lt;strings_not_equal+94&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401372 &amp;lt;+58&amp;gt;: add    $0x1,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401376 &amp;lt;+62&amp;gt;: add    $0x1,%rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040137a &amp;lt;+66&amp;gt;: movzbl (%rbx),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040137d &amp;lt;+69&amp;gt;: test   %al,%al
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040137f &amp;lt;+71&amp;gt;: jne    0x40136a &amp;lt;strings_not_equal+50&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401381 &amp;lt;+73&amp;gt;: mov    $0x0,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401386 &amp;lt;+78&amp;gt;: jmp    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401388 &amp;lt;+80&amp;gt;: mov    $0x0,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040138d &amp;lt;+85&amp;gt;: jmp    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040138f &amp;lt;+87&amp;gt;: mov    $0x1,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401394 &amp;lt;+92&amp;gt;: jmp    0x40139b &amp;lt;strings_not_equal+99&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401396 &amp;lt;+94&amp;gt;: mov    $0x1,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139b &amp;lt;+99&amp;gt;: mov    %edx,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139d &amp;lt;+101&amp;gt;: pop    %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139e &amp;lt;+102&amp;gt;: pop    %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040139f &amp;lt;+103&amp;gt;: pop    %r12
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004013a1 &amp;lt;+105&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3-5：在函数调用时先保存相关寄存器值，&lt;code&gt;rbp&lt;/code&gt;和&lt;code&gt;rbx&lt;/code&gt;就是用来保存两个参数的寄存器&lt;/li&gt;
&lt;li&gt;6：将寄存器&lt;code&gt;rdi&lt;/code&gt;的值复制到寄存器&lt;code&gt;rbp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;7：将寄存器&lt;code&gt;rsi&lt;/code&gt;的值复制到寄存器&lt;code&gt;rbx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其实看到这里就一直能够猜到答案是什么了。我们通过之前的&lt;code&gt;phase_1&lt;/code&gt;函数能够大概知道需要输入一个值进行比较，如果比较正确就能解除炸弹。现在我们又进入到了这个比较函数，比较函数有两个参数，分别保存在两个寄存器里。我们正常的思维如果写一个比较函数，肯定一个参数是我们输入的值，一个参数是正确的值。&lt;/p&gt;
&lt;p&gt;这里看到了&lt;code&gt;rsi&lt;/code&gt;寄存器，我们还记得在&lt;code&gt;phase_1&lt;/code&gt;函数中第 4 行的&lt;code&gt;esi&lt;/code&gt;寄存器吗？这两个寄存器是同一个寄存器，只不过&lt;code&gt;esi&lt;/code&gt;是寄存器的低 32 位，既然&lt;code&gt;esi&lt;/code&gt;已经赋值了，那剩下的一个参数保存我们输入的内容。所以&lt;code&gt;esi&lt;/code&gt;内存的内容就是我们需要的正确答案。我们只要把寄存器&lt;code&gt;esi&lt;/code&gt;中的值打印出来，或者内存地址为&lt;code&gt;0x402400&lt;/code&gt;的内容打印出来即可。可以通过以下三条命令查看。&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p (char*)($esi)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$5 = 0x402400 &amp;#34;Border relations with Canada have never been better.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) x/s 0x402400
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x402400: &amp;#34;Border relations with Canada have never been better.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) x/s $esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0x402400: &amp;#34;Border relations with Canada have never been better.&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将答案复制，然后继续运行&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;The program being debugged has been started already.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Start it from the beginning? (y or n) y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Starting program: /home/dominic/learning-linux/bomb/bomb 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Welcome to my fiendish little bomb. You have 6 phases with
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which to blow yourself up. Have a nice day!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Border relations with Canada have never been better.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 2, 0x0000000000400ee0 in phase_1 ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping until exit from function phase_1,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main (argc=&amp;lt;optimized out&amp;gt;, argv=&amp;lt;optimized out&amp;gt;) at bomb.c:75
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;75     phase_defused();                 /* Drat!  They figured it out!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;77     printf(&amp;#34;Phase 1 defused. How about the next one?\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从 13 行&lt;code&gt;phase_defused()&lt;/code&gt;可以知道我们已经解除了炸弹，从 15 行&lt;code&gt;printf&lt;/code&gt;函数也可以看到，需要进行下一个炸弹的拆除。过来人的建议，在这里就开始分析&lt;code&gt;phase_2&lt;/code&gt;，寻找答案，因为继续执行就要开始输入内容了，将无法调试。&lt;/p&gt;
&lt;h2 id=&#34;phase_2&#34;&gt;phase_2&lt;/h2&gt;
&lt;p&gt;继续分析第二个炸弹，&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas phase_2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function phase_2:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efc &amp;lt;+0&amp;gt;: push   %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efd &amp;lt;+1&amp;gt;: push   %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400efe &amp;lt;+2&amp;gt;: sub    $0x28,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f02 &amp;lt;+6&amp;gt;: mov    %rsp,%rsi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f05 &amp;lt;+9&amp;gt;: callq  0x40145c &amp;lt;read_six_numbers&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f0a &amp;lt;+14&amp;gt;: cmpl   $0x1,(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f0e &amp;lt;+18&amp;gt;: je     0x400f30 &amp;lt;phase_2+52&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f10 &amp;lt;+20&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f15 &amp;lt;+25&amp;gt;: jmp    0x400f30 &amp;lt;phase_2+52&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f17 &amp;lt;+27&amp;gt;: mov    -0x4(%rbx),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f1a &amp;lt;+30&amp;gt;: add    %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f1c &amp;lt;+32&amp;gt;: cmp    %eax,(%rbx)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f1e &amp;lt;+34&amp;gt;: je     0x400f25 &amp;lt;phase_2+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f20 &amp;lt;+36&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f25 &amp;lt;+41&amp;gt;: add    $0x4,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f29 &amp;lt;+45&amp;gt;: cmp    %rbp,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f2c &amp;lt;+48&amp;gt;: jne    0x400f17 &amp;lt;phase_2+27&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f2e &amp;lt;+50&amp;gt;: jmp    0x400f3c &amp;lt;phase_2+64&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f30 &amp;lt;+52&amp;gt;: lea    0x4(%rsp),%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f35 &amp;lt;+57&amp;gt;: lea    0x18(%rsp),%rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f3a &amp;lt;+62&amp;gt;: jmp    0x400f17 &amp;lt;phase_2+27&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f3c &amp;lt;+64&amp;gt;: add    $0x28,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f40 &amp;lt;+68&amp;gt;: pop    %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f41 &amp;lt;+69&amp;gt;: pop    %rbp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f42 &amp;lt;+70&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3-6：保存程序入口地址，变量等内容，就不再赘述了&lt;/li&gt;
&lt;li&gt;7: 调用&lt;code&gt;read_six_numbers&lt;/code&gt;函数，根据函数名我们可以猜测这个函数需要读入六个数字&lt;/li&gt;
&lt;li&gt;8-9：比较寄存器&lt;code&gt;rsp&lt;/code&gt;存的第一个数字是否等于&lt;code&gt;0x1&lt;/code&gt;，如果等于就跳转到&lt;code&gt;phase_2+52&lt;/code&gt;处继续执行，如果不等于就执行&lt;code&gt;explode_bomb&lt;/code&gt;。栈中保存了六个输入的数字，保存顺序是从右往左，假如输入&lt;code&gt;1,2,3,4,5,6&lt;/code&gt;。那么入栈的顺序就是&lt;code&gt;6,5,4,3,2,1&lt;/code&gt;，寄存器&lt;code&gt;rsp&lt;/code&gt;指向栈顶，也就是数字&lt;code&gt;1&lt;/code&gt;的地址。&lt;/li&gt;
&lt;li&gt;21:假设第一个数字正确，我们跳转到&lt;code&gt;&amp;lt;+52&amp;gt;&lt;/code&gt;位置，也就是第 21 行，将&lt;code&gt;rsp+0x4&lt;/code&gt;写入寄存器&lt;code&gt;rbx&lt;/code&gt;，栈指针向上移动四个字节，也就是取第二个输入的参数，将它赋给寄存器&lt;code&gt;rbx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;22：将&lt;code&gt;rsp+0x18&lt;/code&gt;写入寄存器&lt;code&gt;rbp&lt;/code&gt;，十六进制&lt;code&gt;0x18=24&lt;/code&gt;，4 个字节一个数，刚好 6 个数，就是将输入参数的最后一个位置赋给寄存器&lt;code&gt;rbp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;23：跳到&lt;code&gt;phase_2+27&lt;/code&gt;继续执行&lt;/li&gt;
&lt;li&gt;12：&lt;code&gt;rbx-0x4&lt;/code&gt;赋给寄存器&lt;code&gt;eax&lt;/code&gt;。第 21 行我们知道，&lt;code&gt;rbx&lt;/code&gt;此时已经到第二个参数了，这一句就是说把第一个参数的值写入寄存器&lt;code&gt;eax&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;13：将&lt;code&gt;eax&lt;/code&gt;翻一倍，第 8 行知道第一个参数值为&lt;code&gt;1&lt;/code&gt;，所以此时&lt;code&gt;eax&lt;/code&gt;值为&lt;code&gt;2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;14-15：比较&lt;code&gt;eax&lt;/code&gt;是否等于&lt;code&gt;rbx&lt;/code&gt;。&lt;code&gt;rbx&lt;/code&gt;此时保存的是第二个参数，这里也就是比较第二个参数是否等于&lt;code&gt;2&lt;/code&gt;。如果等于跳转到&lt;code&gt;phase_2+41&lt;/code&gt;位置，如果不等于就调用爆炸函数&lt;/li&gt;
&lt;li&gt;17-18：假设第二个参数就是 2，我们跳过了炸弹来到第 17 行，将&lt;code&gt;rbx&lt;/code&gt;继续上移，然后比较&lt;code&gt;rbp&lt;/code&gt;是否等于&lt;code&gt;rbx&lt;/code&gt;，我们知道&lt;code&gt;rbp&lt;/code&gt;保存了最后一个参数的地址，所以这里的意思就是看看参数有没有到最后一个参数。&lt;/li&gt;
&lt;li&gt;19：如果&lt;code&gt;rbx&amp;lt;rbp&lt;/code&gt;，意思就是还没到最后一个参数，就跳转到&lt;code&gt;phase_2+27&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;12：再次回到第 12 行，这里就是相当于一个循环了，让&lt;code&gt;rbx&lt;/code&gt;一直向上移动，分别存入第 2，3，4，5，6 个参数，在移动到下一个参数时先保存当前参数到寄存器&lt;code&gt;eax&lt;/code&gt;让其翻一倍，然后&lt;code&gt;rbx&lt;/code&gt;再移动到下一个参数，比较&lt;code&gt;eax==rbx&lt;/code&gt;。直到&lt;code&gt;rbx&lt;/code&gt;越过了&lt;code&gt;rbp&lt;/code&gt;。程序跳转到&lt;code&gt;phase_2+64&lt;/code&gt;，将栈空间恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上分析也可以得出答案了，我们只要输入一个以&lt;code&gt;1&lt;/code&gt;为初值，公比为&lt;code&gt;2&lt;/code&gt;，个数为&lt;code&gt;6&lt;/code&gt;的等比数列就是答案，也就是&lt;code&gt;1 2 4 8 16 32&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Continuing.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Phase &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; defused. How about the next one?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 6, 0x00000000004015c4 in phase_defused &lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping &lt;span class=&#34;k&#34;&gt;until&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; from &lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; phase_defused,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;argc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;lt;optimized out&amp;gt;, &lt;span class=&#34;nv&#34;&gt;argv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&amp;lt;optimized out&amp;gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; at bomb.c:84
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;84&lt;/span&gt;     printf&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;That&amp;#39;s number 2.  Keep going!\n&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个炸弹的作者应该再心狠手辣一点，把函数名换成&lt;code&gt;read_some_numbers&lt;/code&gt;，这样我们就不得不看这个函数的内容了，因为这个函数里还有一个坑，这个坑在函数名字上一句被填了。那就是这个函数会对参数个数做判断，如果小于 5 就爆炸。&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas read_six_numbers
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function read_six_numbers:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040145c &amp;lt;+0&amp;gt;: sub    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401460 &amp;lt;+4&amp;gt;: mov    %rsi,%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401463 &amp;lt;+7&amp;gt;: lea    0x4(%rsi),%rcx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401467 &amp;lt;+11&amp;gt;: lea    0x14(%rsi),%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040146b &amp;lt;+15&amp;gt;: mov    %rax,0x8(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401470 &amp;lt;+20&amp;gt;: lea    0x10(%rsi),%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401474 &amp;lt;+24&amp;gt;: mov    %rax,(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401478 &amp;lt;+28&amp;gt;: lea    0xc(%rsi),%r9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040147c &amp;lt;+32&amp;gt;: lea    0x8(%rsi),%r8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401480 &amp;lt;+36&amp;gt;: mov    $0x4025c3,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401485 &amp;lt;+41&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040148a &amp;lt;+46&amp;gt;: callq  0x400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040148f &amp;lt;+51&amp;gt;: cmp    $0x5,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401492 &amp;lt;+54&amp;gt;: jg     0x401499 &amp;lt;read_six_numbers+61&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401494 &amp;lt;+56&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401499 &amp;lt;+61&amp;gt;: add    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040149d &amp;lt;+65&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;End of assembler dump.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;3：申请 24 个字节栈空间&lt;/li&gt;
&lt;li&gt;4：&lt;code&gt;rdx=rsi&lt;/code&gt;，将输入参数的第一个参数放到寄存器&lt;code&gt;rdx&lt;/code&gt;中，为啥是第一个参数，因为&lt;code&gt;rsi&lt;/code&gt;现在保存的地址是栈顶位置，栈顶目前保存就是第一个参数。&lt;/li&gt;
&lt;li&gt;5：&lt;code&gt;rcx = rsi + 4&lt;/code&gt;，把第二个参数的地址传给寄存器&lt;code&gt;rcx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;6：&lt;code&gt;rax = rsi + 20&lt;/code&gt;，把第六个参数的地址传给寄存器&lt;code&gt;rax&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;7：&lt;code&gt;rsp + 8 = rax&lt;/code&gt;第八个参数&lt;/li&gt;
&lt;li&gt;8：&lt;code&gt;rax = rsi + 16&lt;/code&gt;，把第五个参数传给&lt;/li&gt;
&lt;li&gt;9：&lt;code&gt;rsp = rax&lt;/code&gt;第七个参数&lt;/li&gt;
&lt;li&gt;10：&lt;code&gt;r9 = rsi + 12&lt;/code&gt;把第四个参数传给寄存器&lt;code&gt;r9&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;11：&lt;code&gt;r8 = rsi + 8&lt;/code&gt;把第三个参数传给寄存器&lt;code&gt;r8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;12：&lt;/li&gt;
&lt;li&gt;13：&lt;code&gt;eax = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;14：调用输入函数&lt;code&gt;sscanf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;15-17：函数返回值个数与 5 比较，如果小于 5 就爆炸，否则返回&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;phase_3&#34;&gt;phase_3&lt;/h2&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f43 &amp;lt;+0&amp;gt;: sub    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f47 &amp;lt;+4&amp;gt;: lea    0xc(%rsp),%rcx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f4c &amp;lt;+9&amp;gt;: lea    0x8(%rsp),%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f51 &amp;lt;+14&amp;gt;: mov    $0x4025cf,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f56 &amp;lt;+19&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f5b &amp;lt;+24&amp;gt;: callq  0x400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f60 &amp;lt;+29&amp;gt;: cmp    $0x1,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f63 &amp;lt;+32&amp;gt;: jg     0x400f6a &amp;lt;phase_3+39&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f65 &amp;lt;+34&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f6a &amp;lt;+39&amp;gt;: cmpl   $0x7,0x8(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f6f &amp;lt;+44&amp;gt;: ja     0x400fad &amp;lt;phase_3+106&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f71 &amp;lt;+46&amp;gt;: mov    0x8(%rsp),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f75 &amp;lt;+50&amp;gt;: jmpq   *0x402470(,%rax,8)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f7c &amp;lt;+57&amp;gt;: mov    $0xcf,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f81 &amp;lt;+62&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f83 &amp;lt;+64&amp;gt;: mov    $0x2c3,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f88 &amp;lt;+69&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f8a &amp;lt;+71&amp;gt;: mov    $0x100,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f8f &amp;lt;+76&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f91 &amp;lt;+78&amp;gt;: mov    $0x185,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f96 &amp;lt;+83&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f98 &amp;lt;+85&amp;gt;: mov    $0xce,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f9d &amp;lt;+90&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400f9f &amp;lt;+92&amp;gt;: mov    $0x2aa,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fa4 &amp;lt;+97&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fa6 &amp;lt;+99&amp;gt;: mov    $0x147,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fab &amp;lt;+104&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fad &amp;lt;+106&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fb2 &amp;lt;+111&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fb7 &amp;lt;+116&amp;gt;: jmp    0x400fbe &amp;lt;phase_3+123&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fb9 &amp;lt;+118&amp;gt;: mov    $0x137,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fbe &amp;lt;+123&amp;gt;: cmp    0xc(%rsp),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fc2 &amp;lt;+127&amp;gt;: je     0x400fc9 &amp;lt;phase_3+134&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fc4 &amp;lt;+129&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fc9 &amp;lt;+134&amp;gt;: add    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fcd &amp;lt;+138&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;1：开辟 24 字节的栈空间&lt;/li&gt;
&lt;li&gt;2：&lt;code&gt;rcx = rsp + 12&lt;/code&gt;第二个参数&lt;/li&gt;
&lt;li&gt;3：&lt;code&gt;rdx = rsp + 8&lt;/code&gt;第一个参数&lt;/li&gt;
&lt;li&gt;4-8：和&lt;code&gt;phase_2&lt;/code&gt;里&lt;code&gt;read_six_numbers&lt;/code&gt;函数中的第 13 行开始一样，输入数据，判断一下输入参数的个数，只不过这里是返回值个数大于 1，如果参数个数正确就跳到&lt;code&gt;phase_3+39&lt;/code&gt;也就是第 10 行，否则引爆炸弹。&lt;/li&gt;
&lt;li&gt;10-11：如果&lt;code&gt;7 &amp;lt; rsp + 8 等价于 7 &amp;lt; rdx 等价于 7 &amp;lt; 第一个参数&lt;/code&gt;就跳转到&lt;code&gt;phase_3+106&lt;/code&gt;，爆炸。这里确定第一个数必须小于 7&lt;/li&gt;
&lt;li&gt;12：&lt;code&gt;eax = rsp + 8 等价于 eax = 第一个参数&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;13：跳转至&lt;code&gt;0x402470 + 8 * rax&lt;/code&gt;处，具体跳转到哪里根据第一个值做判断&lt;/li&gt;
&lt;li&gt;14：&lt;code&gt;eax = 207&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;15：跳转至&lt;code&gt;phase_3+123&lt;/code&gt;,即 32 行&lt;/li&gt;
&lt;li&gt;16：&lt;code&gt;eax = 707&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;17：跳转到 32 行&lt;/li&gt;
&lt;li&gt;18：&lt;code&gt;eax = 256&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;19：跳转到 32 行&lt;/li&gt;
&lt;li&gt;20：&lt;code&gt;eax = 389&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;21-27：以此类推&lt;/li&gt;
&lt;li&gt;29：&lt;code&gt;eax = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;30：&lt;/li&gt;
&lt;li&gt;31：&lt;code&gt;eax = 311&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;32-34：比较&lt;code&gt;eax&lt;/code&gt;和&lt;code&gt;rsp + 12&lt;/code&gt; 等价于 比较 第二个参数和&lt;code&gt;eax&lt;/code&gt;。如果相等就返回，如果不等就引爆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;分析至此，我们也就知道了程序的大概流程，输入两个值，第一个值必须小于等于 7，第二个值根据第一个值来确定，具体等于多少，根据跳转表确定，因为第一个值有八个数，也就对应着汇编中八段寄存器&lt;code&gt;eax&lt;/code&gt;赋值的过程，我们只要输入第一个合法的数值，然后再打印出寄存器&lt;code&gt;eax&lt;/code&gt;的值，即可确定答案。&lt;/p&gt;
&lt;p&gt;比如我们先测试一下第一个值为 0 时，对应的第二个值为多少，我们输入&lt;code&gt;0  10&lt;/code&gt;，因为只是测试，第二个值任意。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;That&amp;#39;s number 2.  Keep going! //接上个炸弹后面
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;88     input = read_line();
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 10              //输入测试答案
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;89     phase_3(input);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 4, 0x0000000000400f43 in phase_3 ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping until exit from function phase_3,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 2, 0x000000000040143a in explode_bomb ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p $eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$14 = 207         //207即是答案
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输入真正答案测试，&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 207                         //输入答案
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;89     phase_3(input);
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint 4, 0x0000000000400f43 in phase_3 ()
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) n
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Single stepping until exit from function phase_3,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which has no line number information.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;main (argc=&amp;lt;optimized out&amp;gt;, argv=&amp;lt;optimized out&amp;gt;) at bomb.c:90
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;90     phase_defused();    //炸弹拆除
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;91     printf(&amp;#34;Halfway there!\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们上面说过，第一个值有八种可能，所以这题答案也有八个，我们只要挨个测试&lt;code&gt;0-7&lt;/code&gt;，分别打印出寄存器&lt;code&gt;eax&lt;/code&gt;的值就可以得到所有答案。他们分别是&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0 207
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1 311
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2 707
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3 256
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4 389
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;5 206
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;6 682
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;7 327
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;phase_4&#34;&gt;phase_4&lt;/h2&gt;
&lt;p&gt;行百里者半九十，NO&lt;/p&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas phase_4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function phase_4:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040100c &amp;lt;+0&amp;gt;: sub    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401010 &amp;lt;+4&amp;gt;: lea    0xc(%rsp),%rcx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401015 &amp;lt;+9&amp;gt;: lea    0x8(%rsp),%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040101a &amp;lt;+14&amp;gt;: mov    $0x4025cf,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040101f &amp;lt;+19&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401024 &amp;lt;+24&amp;gt;: callq  0x400bf0 &amp;lt;__isoc99_sscanf@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401029 &amp;lt;+29&amp;gt;: cmp    $0x2,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040102c &amp;lt;+32&amp;gt;: jne    0x401035 &amp;lt;phase_4+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040102e &amp;lt;+34&amp;gt;: cmpl   $0xe,0x8(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401033 &amp;lt;+39&amp;gt;: jbe    0x40103a &amp;lt;phase_4+46&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401035 &amp;lt;+41&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040103a &amp;lt;+46&amp;gt;: mov    $0xe,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040103f &amp;lt;+51&amp;gt;: mov    $0x0,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401044 &amp;lt;+56&amp;gt;: mov    0x8(%rsp),%edi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401048 &amp;lt;+60&amp;gt;: callq  0x400fce &amp;lt;func4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040104d &amp;lt;+65&amp;gt;: test   %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040104f &amp;lt;+67&amp;gt;: jne    0x401058 &amp;lt;phase_4+76&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401051 &amp;lt;+69&amp;gt;: cmpl   $0x0,0xc(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401056 &amp;lt;+74&amp;gt;: je     0x40105d &amp;lt;phase_4+81&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401058 &amp;lt;+76&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040105d &amp;lt;+81&amp;gt;: add    $0x18,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401061 &amp;lt;+85&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;1-8：开辟空间，保存参数信息，调用输入函数，和上面的分析重复，不再赘述。注意的是第 6 行，&lt;code&gt;x/s 0x4025cf&lt;/code&gt;可知两个参数是整型数值。&lt;/li&gt;
&lt;li&gt;9-10：参数个数必须等于 2，否则引爆&lt;/li&gt;
&lt;li&gt;11-12：&lt;code&gt;14&lt;/code&gt;与&lt;code&gt;rsp + 8&lt;/code&gt;比较，等价于&lt;code&gt;14&lt;/code&gt;与第一个参数比较。表示第一个参数必须小于等于 14，否则引爆。&lt;/li&gt;
&lt;li&gt;14：&lt;code&gt;edx = 14&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;15：&lt;code&gt;esi = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;16：&lt;code&gt;edi = rsp + 8&lt;/code&gt;即&lt;code&gt;edi = 第一个参数&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;17：调用函数&lt;code&gt;fun4&lt;/code&gt;，参数分别为&lt;code&gt;edi 0 14&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;18：测试返回值是否为 0，如果不为 0，引爆&lt;/li&gt;
&lt;li&gt;20-22：比较&lt;code&gt;0&lt;/code&gt;和&lt;code&gt;rsp + 12&lt;/code&gt;，如果不等，引爆，否则返回&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) disas func4
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Dump of assembler code for function func4:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fce &amp;lt;+0&amp;gt;: sub    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd2 &amp;lt;+4&amp;gt;: mov    %edx,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd4 &amp;lt;+6&amp;gt;: sub    %esi,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd6 &amp;lt;+8&amp;gt;: mov    %eax,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fd8 &amp;lt;+10&amp;gt;: shr    $0x1f,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fdb &amp;lt;+13&amp;gt;: add    %ecx,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fdd &amp;lt;+15&amp;gt;: sar    %eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fdf &amp;lt;+17&amp;gt;: lea    (%rax,%rsi,1),%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe2 &amp;lt;+20&amp;gt;: cmp    %edi,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe4 &amp;lt;+22&amp;gt;: jle    0x400ff2 &amp;lt;func4+36&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe6 &amp;lt;+24&amp;gt;: lea    -0x1(%rcx),%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fe9 &amp;lt;+27&amp;gt;: callq  0x400fce &amp;lt;func4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400fee &amp;lt;+32&amp;gt;: add    %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff0 &amp;lt;+34&amp;gt;: jmp    0x401007 &amp;lt;func4+57&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff2 &amp;lt;+36&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff7 &amp;lt;+41&amp;gt;: cmp    %edi,%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ff9 &amp;lt;+43&amp;gt;: jge    0x401007 &amp;lt;func4+57&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ffb &amp;lt;+45&amp;gt;: lea    0x1(%rcx),%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000400ffe &amp;lt;+48&amp;gt;: callq  0x400fce &amp;lt;func4&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401003 &amp;lt;+53&amp;gt;: lea    0x1(%rax,%rax,1),%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401007 &amp;lt;+57&amp;gt;: add    $0x8,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040100b &amp;lt;+61&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-C&#34; data-lang=&#34;C&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;c1&#34;&gt;// edi = 第一个参数, esi = 0, edx = 14
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// 4:mov %edx, %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 5:sub esi, %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt;            &lt;span class=&#34;c1&#34;&gt;// 6:mov %eax, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eсx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 7:shr  $0x1f, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt;      &lt;span class=&#34;c1&#34;&gt;// 8:add %ecx, %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//替换eax和ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;       &lt;span class=&#34;c1&#34;&gt;// 9:sar %eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;   &lt;span class=&#34;c1&#34;&gt;// 10:lea (rax,ersi,1), %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;edx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;esi&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;((&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;c1&#34;&gt;// 11:cmp %edi, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// 12:jle 400ff2
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;eax&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// mov $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// 18:cmp %edi, %ecx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ecx&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;edi&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;c1&#34;&gt;// 19:jge    0x401007 &amp;lt;func4+57&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;         &lt;span class=&#34;c1&#34;&gt;//由此可以得知道 edx == edi
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;phase_5&#34;&gt;phase_5&lt;/h2&gt;
&lt;div class=&#34;highlight line-numbers&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401062 &amp;lt;+0&amp;gt;: push   %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401063 &amp;lt;+1&amp;gt;: sub    $0x20,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401067 &amp;lt;+5&amp;gt;: mov    %rdi,%rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040106a &amp;lt;+8&amp;gt;: mov    %fs:0x28,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401073 &amp;lt;+17&amp;gt;: mov    %rax,0x18(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401078 &amp;lt;+22&amp;gt;: xor    %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040107a &amp;lt;+24&amp;gt;: callq  0x40131b &amp;lt;string_length&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040107f &amp;lt;+29&amp;gt;: cmp    $0x6,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401082 &amp;lt;+32&amp;gt;: je     0x4010d2 &amp;lt;phase_5+112&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401084 &amp;lt;+34&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401089 &amp;lt;+39&amp;gt;: jmp    0x4010d2 &amp;lt;phase_5+112&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040108b &amp;lt;+41&amp;gt;: movzbl (%rbx,%rax,1),%ecx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x000000000040108f &amp;lt;+45&amp;gt;: mov    %cl,(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401092 &amp;lt;+48&amp;gt;: mov    (%rsp),%rdx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401096 &amp;lt;+52&amp;gt;: and    $0xf,%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x0000000000401099 &amp;lt;+55&amp;gt;: movzbl 0x4024b0(%rdx),%edx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010a0 &amp;lt;+62&amp;gt;: mov    %dl,0x10(%rsp,%rax,1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010a4 &amp;lt;+66&amp;gt;: add    $0x1,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010a8 &amp;lt;+70&amp;gt;: cmp    $0x6,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010ac &amp;lt;+74&amp;gt;: jne    0x40108b &amp;lt;phase_5+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010ae &amp;lt;+76&amp;gt;: movb   $0x0,0x16(%rsp)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010b3 &amp;lt;+81&amp;gt;: mov    $0x40245e,%esi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      0x00000000004010b8 &amp;lt;+86&amp;gt;: lea    0x10(%rsp),%rdi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010bd &amp;lt;+91&amp;gt;: callq  0x401338 &amp;lt;strings_not_equal&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010c2 &amp;lt;+96&amp;gt;: test   %eax,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010c4 &amp;lt;+98&amp;gt;: je     0x4010d9 &amp;lt;phase_5+119&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010c6 &amp;lt;+100&amp;gt;: callq  0x40143a &amp;lt;explode_bomb&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010cb &amp;lt;+105&amp;gt;: nopl   0x0(%rax,%rax,1)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d0 &amp;lt;+110&amp;gt;: jmp    0x4010d9 &amp;lt;phase_5+119&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d2 &amp;lt;+112&amp;gt;: mov    $0x0,%eax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d7 &amp;lt;+117&amp;gt;: jmp    0x40108b &amp;lt;phase_5+41&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010d9 &amp;lt;+119&amp;gt;: mov    0x18(%rsp),%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010de &amp;lt;+124&amp;gt;: xor    %fs:0x28,%rax
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010e7 &amp;lt;+133&amp;gt;: je     0x4010ee &amp;lt;phase_5+140&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010e9 &amp;lt;+135&amp;gt;: callq  0x400b30 &amp;lt;__stack_chk_fail@plt&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010ee &amp;lt;+140&amp;gt;: add    $0x20,%rsp
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010f2 &amp;lt;+144&amp;gt;: pop    %rbx
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   0x00000000004010f3 &amp;lt;+145&amp;gt;: retq   
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<h2 id="tips">Tips</h2>
<h3 id="缩写注释">缩写注释</h3>
<p>CSAPP：Computer Systems A Programmer’s Perspective（深入理解计算机操作系统）。CSAPP（C：P166，O：P278）表示书本的中文版第 166 页，英文原版第 278 页。</p>
<h3 id="寄存器信息">寄存器信息</h3>
<p>了解寄存器的基本用途，看到一个汇编代码，可以大概了解这个寄存器是在栈中使用的，还是保存参数的，是调用者保存，还是被调用者保存。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830160500.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<div STYLE="page-break-after: always;"></div>
<h3 id="gdb">GDB</h3>
<p>调试过程用到的 GDB 命令可以先参考<a href="https://dunky-z.github.io/2021/08/29/GDB%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/">GDB 调试入门</a>这篇文章。文中所用例子也是摘自与 BombLab 的源码，更容易理解如何使用。还有一定比较重要的是，如何使用 gdb 带参数调试。为了不用每次运行<code>bomb</code>程序都需要重新输入答案，<code>bomb</code>程序可以读取文本信息，在文本文件中写入答案即可免去手动输入。</p>
<h2 id="phase_1">phase_1</h2>
<p>拆弹专家已上线，开干！！！！！！！！！！！！！</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">(gdb) b phase_1
</span></span><span class="line"><span class="cl">(gdb) b explode_bomb
</span></span><span class="line"><span class="cl">(gdb) disas phase_1
</span></span><span class="line"><span class="cl">Dump of assembler code for function phase_1:&#39;
</span></span><span class="line"><span class="cl">   0x0000000000400ee0 &lt;+0&gt;: sub    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400ee4 &lt;+4&gt;: mov    $0x402400,%esi
</span></span><span class="line"><span class="cl">   0x0000000000400ee9 &lt;+9&gt;: callq  0x401338 &lt;strings_not_equal&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400eee &lt;+14&gt;: test   %eax,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400ef0 &lt;+16&gt;: je     0x400ef7 &lt;phase_1+23&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ef2 &lt;+18&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ef7 &lt;+23&gt;: add    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400efb &lt;+27&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span></code></pre></div><ul>
<li>3：将栈指针<code>rsp</code>减去 8 个字节，也就是申请 8 个字节的栈空间</li>
<li>4：将一个立即数存到寄存器<code>esi</code>中</li>
<li>5：调用函数<code>strings_not_equal</code>，该函数第一条语句的地址为<code>0x401338</code>。<code>callq</code>指令的执行过程可参考书本 CSAPP（C：P166，O：P278）</li>
<li>6：使用<code>test</code>命令（同<code>and</code>命令，不修改目标对象的值）来测试<code>eax</code>中的值是否为<code>0</code>，如果为<code>0</code>则跳过引爆炸弹的函数</li>
<li>7：这一句和上一句是一个整体，如果<code>eax==0</code>,就跳转到<code>0x400ef7</code>，这个地址也就是第 9 行的地址，成功跳过了引爆炸弹函数。意思就是我们输入的某个字符串成功匹配，也就是<code>strings_not_equal</code>函数返回值为 0。</li>
<li>8：调用函数<code>explode_bomb</code>，引爆炸弹</li>
<li>9：将栈指针<code>rsp</code>加上 8 个字节，也就是恢复 8 个字节的栈空间</li>
</ul>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas strings_not_equal 
</span></span><span class="line"><span class="cl">Dump of assembler code for function strings_not_equal:
</span></span><span class="line"><span class="cl">=&gt; 0x0000000000401338 &lt;+0&gt;: push   %r12
</span></span><span class="line"><span class="cl">   0x000000000040133a &lt;+2&gt;: push   %rbp
</span></span><span class="line"><span class="cl">   0x000000000040133b &lt;+3&gt;: push   %rbx
</span></span><span class="line"><span class="cl">   0x000000000040133c &lt;+4&gt;: mov    %rdi,%rbx
</span></span><span class="line"><span class="cl">   0x000000000040133f &lt;+7&gt;: mov    %rsi,%rbp
</span></span><span class="line"><span class="cl">   0x0000000000401342 &lt;+10&gt;: callq  0x40131b &lt;string_length&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401347 &lt;+15&gt;: mov    %eax,%r12d
</span></span><span class="line"><span class="cl">   0x000000000040134a &lt;+18&gt;: mov    %rbp,%rdi
</span></span><span class="line"><span class="cl">   0x000000000040134d &lt;+21&gt;: callq  0x40131b &lt;string_length&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401352 &lt;+26&gt;: mov    $0x1,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401357 &lt;+31&gt;: cmp    %eax,%r12d
</span></span><span class="line"><span class="cl">   0x000000000040135a &lt;+34&gt;: jne    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x000000000040135c &lt;+36&gt;: movzbl (%rbx),%eax
</span></span><span class="line"><span class="cl">   0x000000000040135f &lt;+39&gt;: test   %al,%al
</span></span><span class="line"><span class="cl">   0x0000000000401361 &lt;+41&gt;: je     0x401388 &lt;strings_not_equal+80&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401363 &lt;+43&gt;: cmp    0x0(%rbp),%al
</span></span><span class="line"><span class="cl">   0x0000000000401366 &lt;+46&gt;: je     0x401372 &lt;strings_not_equal+58&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401368 &lt;+48&gt;: jmp    0x40138f &lt;strings_not_equal+87&gt;
</span></span><span class="line"><span class="cl">   0x000000000040136a &lt;+50&gt;: cmp    0x0(%rbp),%al
</span></span><span class="line"><span class="cl">   0x000000000040136d &lt;+53&gt;: nopl   (%rax)
</span></span><span class="line"><span class="cl">   0x0000000000401370 &lt;+56&gt;: jne    0x401396 &lt;strings_not_equal+94&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401372 &lt;+58&gt;: add    $0x1,%rbx
</span></span><span class="line"><span class="cl">   0x0000000000401376 &lt;+62&gt;: add    $0x1,%rbp
</span></span><span class="line"><span class="cl">   0x000000000040137a &lt;+66&gt;: movzbl (%rbx),%eax
</span></span><span class="line"><span class="cl">   0x000000000040137d &lt;+69&gt;: test   %al,%al
</span></span><span class="line"><span class="cl">   0x000000000040137f &lt;+71&gt;: jne    0x40136a &lt;strings_not_equal+50&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401381 &lt;+73&gt;: mov    $0x0,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401386 &lt;+78&gt;: jmp    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401388 &lt;+80&gt;: mov    $0x0,%edx
</span></span><span class="line"><span class="cl">   0x000000000040138d &lt;+85&gt;: jmp    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x000000000040138f &lt;+87&gt;: mov    $0x1,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401394 &lt;+92&gt;: jmp    0x40139b &lt;strings_not_equal+99&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401396 &lt;+94&gt;: mov    $0x1,%edx
</span></span><span class="line"><span class="cl">   0x000000000040139b &lt;+99&gt;: mov    %edx,%eax
</span></span><span class="line"><span class="cl">   0x000000000040139d &lt;+101&gt;: pop    %rbx
</span></span><span class="line"><span class="cl">   0x000000000040139e &lt;+102&gt;: pop    %rbp
</span></span><span class="line"><span class="cl">   0x000000000040139f &lt;+103&gt;: pop    %r12
</span></span><span class="line"><span class="cl">   0x00000000004013a1 &lt;+105&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span><span class="line"><span class="cl">       
</span></span></code></pre></div><ul>
<li>3-5：在函数调用时先保存相关寄存器值，<code>rbp</code>和<code>rbx</code>就是用来保存两个参数的寄存器</li>
<li>6：将寄存器<code>rdi</code>的值复制到寄存器<code>rbp</code></li>
<li>7：将寄存器<code>rsi</code>的值复制到寄存器<code>rbx</code></li>
</ul>
<p>其实看到这里就一直能够猜到答案是什么了。我们通过之前的<code>phase_1</code>函数能够大概知道需要输入一个值进行比较，如果比较正确就能解除炸弹。现在我们又进入到了这个比较函数，比较函数有两个参数，分别保存在两个寄存器里。我们正常的思维如果写一个比较函数，肯定一个参数是我们输入的值，一个参数是正确的值。</p>
<p>这里看到了<code>rsi</code>寄存器，我们还记得在<code>phase_1</code>函数中第 4 行的<code>esi</code>寄存器吗？这两个寄存器是同一个寄存器，只不过<code>esi</code>是寄存器的低 32 位，既然<code>esi</code>已经赋值了，那剩下的一个参数保存我们输入的内容。所以<code>esi</code>内存的内容就是我们需要的正确答案。我们只要把寄存器<code>esi</code>中的值打印出来，或者内存地址为<code>0x402400</code>的内容打印出来即可。可以通过以下三条命令查看。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) p (char*)($esi)
</span></span><span class="line"><span class="cl">$5 = 0x402400 &#34;Border relations with Canada have never been better.&#34;
</span></span><span class="line"><span class="cl">(gdb) x/s 0x402400
</span></span><span class="line"><span class="cl">0x402400: &#34;Border relations with Canada have never been better.&#34;
</span></span><span class="line"><span class="cl">(gdb) x/s $esi
</span></span><span class="line"><span class="cl">0x402400: &#34;Border relations with Canada have never been better.&#34;
</span></span></code></pre></div><p>将答案复制，然后继续运行</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">The program being debugged has been started already.
</span></span><span class="line"><span class="cl">Start it from the beginning? (y or n) y
</span></span><span class="line"><span class="cl">Starting program: /home/dominic/learning-linux/bomb/bomb 
</span></span><span class="line"><span class="cl">Welcome to my fiendish little bomb. You have 6 phases with
</span></span><span class="line"><span class="cl">which to blow yourself up. Have a nice day!
</span></span><span class="line"><span class="cl">Border relations with Canada have never been better.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Breakpoint 2, 0x0000000000400ee0 in phase_1 ()
</span></span><span class="line"><span class="cl">(gdb) s
</span></span><span class="line"><span class="cl">Single stepping until exit from function phase_1,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">main (argc=&lt;optimized out&gt;, argv=&lt;optimized out&gt;) at bomb.c:75
</span></span><span class="line"><span class="cl">75     phase_defused();                 /* Drat!  They figured it out!
</span></span><span class="line"><span class="cl">(gdb) s
</span></span><span class="line"><span class="cl">77     printf(&#34;Phase 1 defused. How about the next one?\n&#34;);
</span></span></code></pre></div><p>从 13 行<code>phase_defused()</code>可以知道我们已经解除了炸弹，从 15 行<code>printf</code>函数也可以看到，需要进行下一个炸弹的拆除。过来人的建议，在这里就开始分析<code>phase_2</code>，寻找答案，因为继续执行就要开始输入内容了，将无法调试。</p>
<h2 id="phase_2">phase_2</h2>
<p>继续分析第二个炸弹，</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas phase_2
</span></span><span class="line"><span class="cl">Dump of assembler code for function phase_2:
</span></span><span class="line"><span class="cl">   0x0000000000400efc &lt;+0&gt;: push   %rbp
</span></span><span class="line"><span class="cl">   0x0000000000400efd &lt;+1&gt;: push   %rbx
</span></span><span class="line"><span class="cl">   0x0000000000400efe &lt;+2&gt;: sub    $0x28,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400f02 &lt;+6&gt;: mov    %rsp,%rsi
</span></span><span class="line"><span class="cl">   0x0000000000400f05 &lt;+9&gt;: callq  0x40145c &lt;read_six_numbers&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f0a &lt;+14&gt;: cmpl   $0x1,(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000400f0e &lt;+18&gt;: je     0x400f30 &lt;phase_2+52&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f10 &lt;+20&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f15 &lt;+25&gt;: jmp    0x400f30 &lt;phase_2+52&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f17 &lt;+27&gt;: mov    -0x4(%rbx),%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f1a &lt;+30&gt;: add    %eax,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f1c &lt;+32&gt;: cmp    %eax,(%rbx)
</span></span><span class="line"><span class="cl">   0x0000000000400f1e &lt;+34&gt;: je     0x400f25 &lt;phase_2+41&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f20 &lt;+36&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f25 &lt;+41&gt;: add    $0x4,%rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f29 &lt;+45&gt;: cmp    %rbp,%rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f2c &lt;+48&gt;: jne    0x400f17 &lt;phase_2+27&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f2e &lt;+50&gt;: jmp    0x400f3c &lt;phase_2+64&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f30 &lt;+52&gt;: lea    0x4(%rsp),%rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f35 &lt;+57&gt;: lea    0x18(%rsp),%rbp
</span></span><span class="line"><span class="cl">   0x0000000000400f3a &lt;+62&gt;: jmp    0x400f17 &lt;phase_2+27&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f3c &lt;+64&gt;: add    $0x28,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400f40 &lt;+68&gt;: pop    %rbx
</span></span><span class="line"><span class="cl">   0x0000000000400f41 &lt;+69&gt;: pop    %rbp
</span></span><span class="line"><span class="cl">   0x0000000000400f42 &lt;+70&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span></code></pre></div><ul>
<li>3-6：保存程序入口地址，变量等内容，就不再赘述了</li>
<li>7: 调用<code>read_six_numbers</code>函数，根据函数名我们可以猜测这个函数需要读入六个数字</li>
<li>8-9：比较寄存器<code>rsp</code>存的第一个数字是否等于<code>0x1</code>，如果等于就跳转到<code>phase_2+52</code>处继续执行，如果不等于就执行<code>explode_bomb</code>。栈中保存了六个输入的数字，保存顺序是从右往左，假如输入<code>1,2,3,4,5,6</code>。那么入栈的顺序就是<code>6,5,4,3,2,1</code>，寄存器<code>rsp</code>指向栈顶，也就是数字<code>1</code>的地址。</li>
<li>21:假设第一个数字正确，我们跳转到<code>&lt;+52&gt;</code>位置，也就是第 21 行，将<code>rsp+0x4</code>写入寄存器<code>rbx</code>，栈指针向上移动四个字节，也就是取第二个输入的参数，将它赋给寄存器<code>rbx</code></li>
<li>22：将<code>rsp+0x18</code>写入寄存器<code>rbp</code>，十六进制<code>0x18=24</code>，4 个字节一个数，刚好 6 个数，就是将输入参数的最后一个位置赋给寄存器<code>rbp</code></li>
<li>23：跳到<code>phase_2+27</code>继续执行</li>
<li>12：<code>rbx-0x4</code>赋给寄存器<code>eax</code>。第 21 行我们知道，<code>rbx</code>此时已经到第二个参数了，这一句就是说把第一个参数的值写入寄存器<code>eax</code></li>
<li>13：将<code>eax</code>翻一倍，第 8 行知道第一个参数值为<code>1</code>，所以此时<code>eax</code>值为<code>2</code></li>
<li>14-15：比较<code>eax</code>是否等于<code>rbx</code>。<code>rbx</code>此时保存的是第二个参数，这里也就是比较第二个参数是否等于<code>2</code>。如果等于跳转到<code>phase_2+41</code>位置，如果不等于就调用爆炸函数</li>
<li>17-18：假设第二个参数就是 2，我们跳过了炸弹来到第 17 行，将<code>rbx</code>继续上移，然后比较<code>rbp</code>是否等于<code>rbx</code>，我们知道<code>rbp</code>保存了最后一个参数的地址，所以这里的意思就是看看参数有没有到最后一个参数。</li>
<li>19：如果<code>rbx&lt;rbp</code>，意思就是还没到最后一个参数，就跳转到<code>phase_2+27</code></li>
<li>12：再次回到第 12 行，这里就是相当于一个循环了，让<code>rbx</code>一直向上移动，分别存入第 2，3，4，5，6 个参数，在移动到下一个参数时先保存当前参数到寄存器<code>eax</code>让其翻一倍，然后<code>rbx</code>再移动到下一个参数，比较<code>eax==rbx</code>。直到<code>rbx</code>越过了<code>rbp</code>。程序跳转到<code>phase_2+64</code>，将栈空间恢复。</li>
</ul>
<p>以上分析也可以得出答案了，我们只要输入一个以<code>1</code>为初值，公比为<code>2</code>，个数为<code>6</code>的等比数列就是答案，也就是<code>1 2 4 8 16 32</code>。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> c
</span></span><span class="line"><span class="cl">Continuing.
</span></span><span class="line"><span class="cl">Phase <span class="m">1</span> defused. How about the next one?
</span></span><span class="line"><span class="cl"><span class="m">1</span> <span class="m">2</span> <span class="m">4</span> <span class="m">8</span> <span class="m">16</span> <span class="m">32</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Breakpoint 6, 0x00000000004015c4 in phase_defused <span class="o">()</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> s
</span></span><span class="line"><span class="cl">Single stepping <span class="k">until</span> <span class="nb">exit</span> from <span class="k">function</span> phase_defused,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">main <span class="o">(</span><span class="nv">argc</span><span class="o">=</span>&lt;optimized out&gt;, <span class="nv">argv</span><span class="o">=</span>&lt;optimized out&gt;<span class="o">)</span> at bomb.c:84
</span></span><span class="line"><span class="cl"><span class="m">84</span>     printf<span class="o">(</span><span class="s2">&#34;That&#39;s number 2.  Keep going!\n&#34;</span><span class="o">)</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> s
</span></span></code></pre></div><p>这个炸弹的作者应该再心狠手辣一点，把函数名换成<code>read_some_numbers</code>，这样我们就不得不看这个函数的内容了，因为这个函数里还有一个坑，这个坑在函数名字上一句被填了。那就是这个函数会对参数个数做判断，如果小于 5 就爆炸。</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas read_six_numbers
</span></span><span class="line"><span class="cl">Dump of assembler code for function read_six_numbers:
</span></span><span class="line"><span class="cl">   0x000000000040145c &lt;+0&gt;: sub    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401460 &lt;+4&gt;: mov    %rsi,%rdx
</span></span><span class="line"><span class="cl">   0x0000000000401463 &lt;+7&gt;: lea    0x4(%rsi),%rcx
</span></span><span class="line"><span class="cl">   0x0000000000401467 &lt;+11&gt;: lea    0x14(%rsi),%rax
</span></span><span class="line"><span class="cl">   0x000000000040146b &lt;+15&gt;: mov    %rax,0x8(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401470 &lt;+20&gt;: lea    0x10(%rsi),%rax
</span></span><span class="line"><span class="cl">   0x0000000000401474 &lt;+24&gt;: mov    %rax,(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401478 &lt;+28&gt;: lea    0xc(%rsi),%r9
</span></span><span class="line"><span class="cl">   0x000000000040147c &lt;+32&gt;: lea    0x8(%rsi),%r8
</span></span><span class="line"><span class="cl">   0x0000000000401480 &lt;+36&gt;: mov    $0x4025c3,%esi
</span></span><span class="line"><span class="cl">   0x0000000000401485 &lt;+41&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x000000000040148a &lt;+46&gt;: callq  0x400bf0 &lt;__isoc99_sscanf@plt&gt;
</span></span><span class="line"><span class="cl">   0x000000000040148f &lt;+51&gt;: cmp    $0x5,%eax
</span></span><span class="line"><span class="cl">   0x0000000000401492 &lt;+54&gt;: jg     0x401499 &lt;read_six_numbers+61&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401494 &lt;+56&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401499 &lt;+61&gt;: add    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x000000000040149d &lt;+65&gt;: retq   
</span></span><span class="line"><span class="cl">End of assembler dump.
</span></span></code></pre></div><ul>
<li>3：申请 24 个字节栈空间</li>
<li>4：<code>rdx=rsi</code>，将输入参数的第一个参数放到寄存器<code>rdx</code>中，为啥是第一个参数，因为<code>rsi</code>现在保存的地址是栈顶位置，栈顶目前保存就是第一个参数。</li>
<li>5：<code>rcx = rsi + 4</code>，把第二个参数的地址传给寄存器<code>rcx</code></li>
<li>6：<code>rax = rsi + 20</code>，把第六个参数的地址传给寄存器<code>rax</code></li>
<li>7：<code>rsp + 8 = rax</code>第八个参数</li>
<li>8：<code>rax = rsi + 16</code>，把第五个参数传给</li>
<li>9：<code>rsp = rax</code>第七个参数</li>
<li>10：<code>r9 = rsi + 12</code>把第四个参数传给寄存器<code>r9</code></li>
<li>11：<code>r8 = rsi + 8</code>把第三个参数传给寄存器<code>r8</code></li>
<li>12：</li>
<li>13：<code>eax = 0</code></li>
<li>14：调用输入函数<code>sscanf</code></li>
<li>15-17：函数返回值个数与 5 比较，如果小于 5 就爆炸，否则返回</li>
</ul>
<h2 id="phase_3">phase_3</h2>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">   0x0000000000400f43 &lt;+0&gt;: sub    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400f47 &lt;+4&gt;: lea    0xc(%rsp),%rcx
</span></span><span class="line"><span class="cl">   0x0000000000400f4c &lt;+9&gt;: lea    0x8(%rsp),%rdx
</span></span><span class="line"><span class="cl">   0x0000000000400f51 &lt;+14&gt;: mov    $0x4025cf,%esi
</span></span><span class="line"><span class="cl">   0x0000000000400f56 &lt;+19&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f5b &lt;+24&gt;: callq  0x400bf0 &lt;__isoc99_sscanf@plt&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f60 &lt;+29&gt;: cmp    $0x1,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f63 &lt;+32&gt;: jg     0x400f6a &lt;phase_3+39&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f65 &lt;+34&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f6a &lt;+39&gt;: cmpl   $0x7,0x8(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000400f6f &lt;+44&gt;: ja     0x400fad &lt;phase_3+106&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f71 &lt;+46&gt;: mov    0x8(%rsp),%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f75 &lt;+50&gt;: jmpq   *0x402470(,%rax,8)
</span></span><span class="line"><span class="cl">   0x0000000000400f7c &lt;+57&gt;: mov    $0xcf,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f81 &lt;+62&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f83 &lt;+64&gt;: mov    $0x2c3,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f88 &lt;+69&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f8a &lt;+71&gt;: mov    $0x100,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f8f &lt;+76&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f91 &lt;+78&gt;: mov    $0x185,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f96 &lt;+83&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f98 &lt;+85&gt;: mov    $0xce,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400f9d &lt;+90&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400f9f &lt;+92&gt;: mov    $0x2aa,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fa4 &lt;+97&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fa6 &lt;+99&gt;: mov    $0x147,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fab &lt;+104&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fad &lt;+106&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fb2 &lt;+111&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fb7 &lt;+116&gt;: jmp    0x400fbe &lt;phase_3+123&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fb9 &lt;+118&gt;: mov    $0x137,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fbe &lt;+123&gt;: cmp    0xc(%rsp),%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fc2 &lt;+127&gt;: je     0x400fc9 &lt;phase_3+134&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fc4 &lt;+129&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fc9 &lt;+134&gt;: add    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400fcd &lt;+138&gt;: retq   
</span></span></code></pre></div><ul>
<li>1：开辟 24 字节的栈空间</li>
<li>2：<code>rcx = rsp + 12</code>第二个参数</li>
<li>3：<code>rdx = rsp + 8</code>第一个参数</li>
<li>4-8：和<code>phase_2</code>里<code>read_six_numbers</code>函数中的第 13 行开始一样，输入数据，判断一下输入参数的个数，只不过这里是返回值个数大于 1，如果参数个数正确就跳到<code>phase_3+39</code>也就是第 10 行，否则引爆炸弹。</li>
<li>10-11：如果<code>7 &lt; rsp + 8 等价于 7 &lt; rdx 等价于 7 &lt; 第一个参数</code>就跳转到<code>phase_3+106</code>，爆炸。这里确定第一个数必须小于 7</li>
<li>12：<code>eax = rsp + 8 等价于 eax = 第一个参数</code></li>
<li>13：跳转至<code>0x402470 + 8 * rax</code>处，具体跳转到哪里根据第一个值做判断</li>
<li>14：<code>eax = 207</code></li>
<li>15：跳转至<code>phase_3+123</code>,即 32 行</li>
<li>16：<code>eax = 707</code></li>
<li>17：跳转到 32 行</li>
<li>18：<code>eax = 256</code></li>
<li>19：跳转到 32 行</li>
<li>20：<code>eax = 389</code></li>
<li>21-27：以此类推</li>
<li>29：<code>eax = 0</code></li>
<li>30：</li>
<li>31：<code>eax = 311</code></li>
<li>32-34：比较<code>eax</code>和<code>rsp + 12</code> 等价于 比较 第二个参数和<code>eax</code>。如果相等就返回，如果不等就引爆。</li>
</ul>
<p>分析至此，我们也就知道了程序的大概流程，输入两个值，第一个值必须小于等于 7，第二个值根据第一个值来确定，具体等于多少，根据跳转表确定，因为第一个值有八个数，也就对应着汇编中八段寄存器<code>eax</code>赋值的过程，我们只要输入第一个合法的数值，然后再打印出寄存器<code>eax</code>的值，即可确定答案。</p>
<p>比如我们先测试一下第一个值为 0 时，对应的第二个值为多少，我们输入<code>0  10</code>，因为只是测试，第二个值任意。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">That&#39;s number 2.  Keep going! //接上个炸弹后面
</span></span><span class="line"><span class="cl">88     input = read_line();
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">0 10              //输入测试答案
</span></span><span class="line"><span class="cl">89     phase_3(input);
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Breakpoint 4, 0x0000000000400f43 in phase_3 ()
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Single stepping until exit from function phase_3,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">Breakpoint 2, 0x000000000040143a in explode_bomb ()
</span></span><span class="line"><span class="cl">(gdb) p $eax
</span></span><span class="line"><span class="cl">$14 = 207         //207即是答案
</span></span></code></pre></div><p>输入真正答案测试，</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">0 207                         //输入答案
</span></span><span class="line"><span class="cl">89     phase_3(input);
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Breakpoint 4, 0x0000000000400f43 in phase_3 ()
</span></span><span class="line"><span class="cl">(gdb) n
</span></span><span class="line"><span class="cl">Single stepping until exit from function phase_3,
</span></span><span class="line"><span class="cl">which has no line number information.
</span></span><span class="line"><span class="cl">main (argc=&lt;optimized out&gt;, argv=&lt;optimized out&gt;) at bomb.c:90
</span></span><span class="line"><span class="cl">90     phase_defused();    //炸弹拆除
</span></span><span class="line"><span class="cl">(gdb) 
</span></span><span class="line"><span class="cl">91     printf(&#34;Halfway there!\n&#34;);
</span></span></code></pre></div><p>我们上面说过，第一个值有八种可能，所以这题答案也有八个，我们只要挨个测试<code>0-7</code>，分别打印出寄存器<code>eax</code>的值就可以得到所有答案。他们分别是</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">0 207
</span></span><span class="line"><span class="cl">1 311
</span></span><span class="line"><span class="cl">2 707
</span></span><span class="line"><span class="cl">3 256
</span></span><span class="line"><span class="cl">4 389
</span></span><span class="line"><span class="cl">5 206
</span></span><span class="line"><span class="cl">6 682
</span></span><span class="line"><span class="cl">7 327
</span></span></code></pre></div><h2 id="phase_4">phase_4</h2>
<p>行百里者半九十，NO</p>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas phase_4
</span></span><span class="line"><span class="cl">Dump of assembler code for function phase_4:
</span></span><span class="line"><span class="cl">   0x000000000040100c &lt;+0&gt;: sub    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401010 &lt;+4&gt;: lea    0xc(%rsp),%rcx
</span></span><span class="line"><span class="cl">   0x0000000000401015 &lt;+9&gt;: lea    0x8(%rsp),%rdx
</span></span><span class="line"><span class="cl">   0x000000000040101a &lt;+14&gt;: mov    $0x4025cf,%esi
</span></span><span class="line"><span class="cl">   0x000000000040101f &lt;+19&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000401024 &lt;+24&gt;: callq  0x400bf0 &lt;__isoc99_sscanf@plt&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401029 &lt;+29&gt;: cmp    $0x2,%eax
</span></span><span class="line"><span class="cl">   0x000000000040102c &lt;+32&gt;: jne    0x401035 &lt;phase_4+41&gt;
</span></span><span class="line"><span class="cl">   0x000000000040102e &lt;+34&gt;: cmpl   $0xe,0x8(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401033 &lt;+39&gt;: jbe    0x40103a &lt;phase_4+46&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401035 &lt;+41&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x000000000040103a &lt;+46&gt;: mov    $0xe,%edx
</span></span><span class="line"><span class="cl">   0x000000000040103f &lt;+51&gt;: mov    $0x0,%esi
</span></span><span class="line"><span class="cl">   0x0000000000401044 &lt;+56&gt;: mov    0x8(%rsp),%edi
</span></span><span class="line"><span class="cl">   0x0000000000401048 &lt;+60&gt;: callq  0x400fce &lt;func4&gt;
</span></span><span class="line"><span class="cl">   0x000000000040104d &lt;+65&gt;: test   %eax,%eax
</span></span><span class="line"><span class="cl">   0x000000000040104f &lt;+67&gt;: jne    0x401058 &lt;phase_4+76&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401051 &lt;+69&gt;: cmpl   $0x0,0xc(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401056 &lt;+74&gt;: je     0x40105d &lt;phase_4+81&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401058 &lt;+76&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x000000000040105d &lt;+81&gt;: add    $0x18,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401061 &lt;+85&gt;: retq   
</span></span></code></pre></div><ul>
<li>1-8：开辟空间，保存参数信息，调用输入函数，和上面的分析重复，不再赘述。注意的是第 6 行，<code>x/s 0x4025cf</code>可知两个参数是整型数值。</li>
<li>9-10：参数个数必须等于 2，否则引爆</li>
<li>11-12：<code>14</code>与<code>rsp + 8</code>比较，等价于<code>14</code>与第一个参数比较。表示第一个参数必须小于等于 14，否则引爆。</li>
<li>14：<code>edx = 14</code></li>
<li>15：<code>esi = 0</code></li>
<li>16：<code>edi = rsp + 8</code>即<code>edi = 第一个参数</code></li>
<li>17：调用函数<code>fun4</code>，参数分别为<code>edi 0 14</code></li>
<li>18：测试返回值是否为 0，如果不为 0，引爆</li>
<li>20-22：比较<code>0</code>和<code>rsp + 12</code>，如果不等，引爆，否则返回</li>
</ul>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) disas func4
</span></span><span class="line"><span class="cl">Dump of assembler code for function func4:
</span></span><span class="line"><span class="cl">   0x0000000000400fce &lt;+0&gt;: sub    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000400fd2 &lt;+4&gt;: mov    %edx,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fd4 &lt;+6&gt;: sub    %esi,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fd6 &lt;+8&gt;: mov    %eax,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fd8 &lt;+10&gt;: shr    $0x1f,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fdb &lt;+13&gt;: add    %ecx,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400fdd &lt;+15&gt;: sar    %eax
</span></span><span class="line"><span class="cl">   0x0000000000400fdf &lt;+17&gt;: lea    (%rax,%rsi,1),%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fe2 &lt;+20&gt;: cmp    %edi,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400fe4 &lt;+22&gt;: jle    0x400ff2 &lt;func4+36&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fe6 &lt;+24&gt;: lea    -0x1(%rcx),%edx
</span></span><span class="line"><span class="cl">   0x0000000000400fe9 &lt;+27&gt;: callq  0x400fce &lt;func4&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400fee &lt;+32&gt;: add    %eax,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400ff0 &lt;+34&gt;: jmp    0x401007 &lt;func4+57&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ff2 &lt;+36&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x0000000000400ff7 &lt;+41&gt;: cmp    %edi,%ecx
</span></span><span class="line"><span class="cl">   0x0000000000400ff9 &lt;+43&gt;: jge    0x401007 &lt;func4+57&gt;
</span></span><span class="line"><span class="cl">   0x0000000000400ffb &lt;+45&gt;: lea    0x1(%rcx),%esi
</span></span><span class="line"><span class="cl">   0x0000000000400ffe &lt;+48&gt;: callq  0x400fce &lt;func4&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401003 &lt;+53&gt;: lea    0x1(%rax,%rax,1),%eax
</span></span><span class="line"><span class="cl">   0x0000000000401007 &lt;+57&gt;: add    $0x8,%rsp
</span></span><span class="line"><span class="cl">   0x000000000040100b &lt;+61&gt;: retq   
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-C" data-lang="C"><span class="line"><span class="cl"><span class="nf">func</span> <span class="p">(</span><span class="n">edi</span><span class="p">,</span> <span class="n">esi</span><span class="p">,</span> <span class="n">edx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="c1">// edi = 第一个参数, esi = 0, edx = 14
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">edx</span>            <span class="c1">// 4:mov %edx, %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">-</span><span class="n">esi</span>       <span class="c1">// 5:sub esi, %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">edx</span> <span class="o">-</span><span class="n">esi</span>
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="n">eax</span>            <span class="c1">// 6:mov %eax, %ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span>
</span></span><span class="line"><span class="cl">   <span class="n">eсx</span> <span class="o">=</span> <span class="n">ecx</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span>      <span class="c1">// 7:shr  $0x1f, %ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="p">(</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span>
</span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">+</span> <span class="n">ecx</span>      <span class="c1">// 8:add %ecx, %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="p">(</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">+</span> <span class="p">((</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">)</span><span class="c1">//替换eax和ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">;</span>       <span class="c1">// 9:sar %eax
</span></span></span><span class="line"><span class="cl">   <span class="n">eax</span> <span class="o">=</span> <span class="p">((</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">+</span><span class="p">((</span><span class="n">edx</span> <span class="o">-</span><span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="n">eax</span> <span class="o">+</span> <span class="n">esi</span> <span class="o">*</span> <span class="mi">1</span>   <span class="c1">// 10:lea (rax,ersi,1), %ecx
</span></span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="p">((</span><span class="n">edx</span> <span class="o">-</span> <span class="n">esi</span><span class="p">)</span> <span class="o">+</span><span class="p">((</span><span class="n">edx</span> <span class="o">-</span><span class="n">esi</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">esi</span> <span class="o">*</span> <span class="mi">1</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="p">((</span><span class="mi">14</span> <span class="o">-</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="p">((</span><span class="mi">14</span> <span class="o">-</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&gt;&gt;</span> <span class="mi">31</span><span class="p">))</span> <span class="o">/</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">   <span class="n">ecx</span> <span class="o">=</span> <span class="mi">7</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="c1">// 11:cmp %edi, %ecx
</span></span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">ecx</span> <span class="o">&lt;=</span> <span class="n">edi</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// 12:jle 400ff2
</span></span></span><span class="line"><span class="cl">      <span class="n">eax</span> <span class="o">=</span> <span class="mi">0</span>    <span class="c1">// mov $0x0,%eax
</span></span></span><span class="line"><span class="cl">      <span class="c1">// 18:cmp %edi, %ecx
</span></span></span><span class="line"><span class="cl">      <span class="k">if</span><span class="p">(</span><span class="n">ecx</span> <span class="o">&gt;=</span> <span class="n">edi</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="c1">// 19:jge    0x401007 &lt;func4+57&gt;
</span></span></span><span class="line"><span class="cl">         <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="c1">//由此可以得知道 edx == edi
</span></span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h2 id="phase_5">phase_5</h2>
<div class="highlight line-numbers"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">   0x0000000000401062 &lt;+0&gt;: push   %rbx
</span></span><span class="line"><span class="cl">   0x0000000000401063 &lt;+1&gt;: sub    $0x20,%rsp
</span></span><span class="line"><span class="cl">   0x0000000000401067 &lt;+5&gt;: mov    %rdi,%rbx
</span></span><span class="line"><span class="cl">   0x000000000040106a &lt;+8&gt;: mov    %fs:0x28,%rax
</span></span><span class="line"><span class="cl">   0x0000000000401073 &lt;+17&gt;: mov    %rax,0x18(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401078 &lt;+22&gt;: xor    %eax,%eax
</span></span><span class="line"><span class="cl">   0x000000000040107a &lt;+24&gt;: callq  0x40131b &lt;string_length&gt;
</span></span><span class="line"><span class="cl">   0x000000000040107f &lt;+29&gt;: cmp    $0x6,%eax
</span></span><span class="line"><span class="cl">   0x0000000000401082 &lt;+32&gt;: je     0x4010d2 &lt;phase_5+112&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401084 &lt;+34&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x0000000000401089 &lt;+39&gt;: jmp    0x4010d2 &lt;phase_5+112&gt;
</span></span><span class="line"><span class="cl">   0x000000000040108b &lt;+41&gt;: movzbl (%rbx,%rax,1),%ecx
</span></span><span class="line"><span class="cl">   0x000000000040108f &lt;+45&gt;: mov    %cl,(%rsp)
</span></span><span class="line"><span class="cl">   0x0000000000401092 &lt;+48&gt;: mov    (%rsp),%rdx
</span></span><span class="line"><span class="cl">   0x0000000000401096 &lt;+52&gt;: and    $0xf,%edx
</span></span><span class="line"><span class="cl">   0x0000000000401099 &lt;+55&gt;: movzbl 0x4024b0(%rdx),%edx
</span></span><span class="line"><span class="cl">   0x00000000004010a0 &lt;+62&gt;: mov    %dl,0x10(%rsp,%rax,1)
</span></span><span class="line"><span class="cl">   0x00000000004010a4 &lt;+66&gt;: add    $0x1,%rax
</span></span><span class="line"><span class="cl">   0x00000000004010a8 &lt;+70&gt;: cmp    $0x6,%rax
</span></span><span class="line"><span class="cl">   0x00000000004010ac &lt;+74&gt;: jne    0x40108b &lt;phase_5+41&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010ae &lt;+76&gt;: movb   $0x0,0x16(%rsp)
</span></span><span class="line"><span class="cl">   0x00000000004010b3 &lt;+81&gt;: mov    $0x40245e,%esi
</span></span><span class="line"><span class="cl">      0x00000000004010b8 &lt;+86&gt;: lea    0x10(%rsp),%rdi
</span></span><span class="line"><span class="cl">   0x00000000004010bd &lt;+91&gt;: callq  0x401338 &lt;strings_not_equal&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010c2 &lt;+96&gt;: test   %eax,%eax
</span></span><span class="line"><span class="cl">   0x00000000004010c4 &lt;+98&gt;: je     0x4010d9 &lt;phase_5+119&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010c6 &lt;+100&gt;: callq  0x40143a &lt;explode_bomb&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010cb &lt;+105&gt;: nopl   0x0(%rax,%rax,1)
</span></span><span class="line"><span class="cl">   0x00000000004010d0 &lt;+110&gt;: jmp    0x4010d9 &lt;phase_5+119&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010d2 &lt;+112&gt;: mov    $0x0,%eax
</span></span><span class="line"><span class="cl">   0x00000000004010d7 &lt;+117&gt;: jmp    0x40108b &lt;phase_5+41&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010d9 &lt;+119&gt;: mov    0x18(%rsp),%rax
</span></span><span class="line"><span class="cl">   0x00000000004010de &lt;+124&gt;: xor    %fs:0x28,%rax
</span></span><span class="line"><span class="cl">   0x00000000004010e7 &lt;+133&gt;: je     0x4010ee &lt;phase_5+140&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010e9 &lt;+135&gt;: callq  0x400b30 &lt;__stack_chk_fail@plt&gt;
</span></span><span class="line"><span class="cl">   0x00000000004010ee &lt;+140&gt;: add    $0x20,%rsp
</span></span><span class="line"><span class="cl">   0x00000000004010f2 &lt;+144&gt;: pop    %rbx
</span></span><span class="line"><span class="cl">   0x00000000004010f3 &lt;+145&gt;: retq   
</span></span></code></pre></div>]]></content:encoded>
    </item>
    <item>
      <title>GDB 调试入门</title>
      <link>https://lifeislife.cn/posts/gdb%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/</link>
      <pubDate>Sun, 29 Aug 2021 18:40:16 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/gdb%E8%B0%83%E8%AF%95%E5%85%A5%E9%97%A8/</guid>
      <description>&lt;h2 id=&#34;file-加载程序&#34;&gt;file 加载程序&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; file bomb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading symbols from bomb...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;set-args-带参数调试&#34;&gt;set args 带参数调试&lt;/h2&gt;
&lt;p&gt;有时候程序不是直接可以运行的，需要加上一些必要的参数。带上参数运行很容易，只要在程序名后加上相应参数即可，但是如何带上参数进行调试呢？这就需要&lt;code&gt;set args&lt;/code&gt;命令。&lt;/p&gt;
&lt;p&gt;比如在&lt;code&gt;BombLab&lt;/code&gt;实验中，我们不可能一次解决所有&lt;code&gt;phase&lt;/code&gt;，但是每次重新调试，已经解决的&lt;code&gt;phase&lt;/code&gt;还要重新输入一次答案，这就很麻烦，好在这个实验的作者也考虑到了，他支持读取文本。我们可以把答案预先写入一个文本文件中，程序读取已经保存的答案即可跳过相应的&lt;code&gt;phase&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;假设我们把答案写入了&lt;code&gt;solutions.txt&lt;/code&gt;文件中，首先，我们加载程序，然后通过&lt;code&gt;set args solutions.txt&lt;/code&gt;设置运行参数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; file bomb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Reading symbols from bomb...
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; args solutions.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; r
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Starting program: /home/dominic/learning-linux/bomb/bomb solutions.txt 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Welcome to my fiendish little bomb. You have &lt;span class=&#34;m&#34;&gt;6&lt;/span&gt; phases with
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;which to blow yourself up. Have a nice day!
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Phase &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; defused. How about the next one?
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;That&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;s number 2.  Keep going!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;list-查看源码&#34;&gt;list 查看源码&lt;/h2&gt;
&lt;h3 id=&#34;查看-10-行源码&#34;&gt;查看 10 行源码&lt;/h3&gt;
&lt;p&gt;每条命令显示 10 行代码&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;#34;support.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;26&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#include &amp;#34;phases.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;27&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; /* 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;29&lt;/span&gt;  * Note to self: Remember to erase this file so my victims will have no
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;30&lt;/span&gt;  * idea what is going on, and so they will all blow up in a
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;31&lt;/span&gt;  * spectaculary fiendish explosion. -- Dr. Evil 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;32&lt;/span&gt;  */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; l
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;33&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;34&lt;/span&gt; FILE *infile&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;35&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;36&lt;/span&gt; int main&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;int argc, char *argv&lt;span class=&#34;o&#34;&gt;[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;37&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;38&lt;/span&gt;     char *input&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;39&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;40&lt;/span&gt;     /* Note to self: remember to port this bomb to Windows and put a 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;41&lt;/span&gt;      * fantastic GUI on it. */
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;42&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;set-list-num-设置默认显示代码行数&#34;&gt;set list num 设置默认显示代码行数&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) set list 20   //默认显示20行代码
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;list-linenumber-查看指定行代码&#34;&gt;list linenumber 查看指定行代码&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) l 10  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) l main.h : 10 //指定main.c文件中的第十行
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;list-function-查看指定函数的代码&#34;&gt;list function 查看指定函数的代码&lt;/h3&gt;
&lt;h2 id=&#34;break-打断点&#34;&gt;break 打断点&lt;/h2&gt;
&lt;h3 id=&#34;break-linenum-对指定行打断点&#34;&gt;break linenum 对指定行打断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; b &lt;span class=&#34;m&#34;&gt;36&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Note: breakpoint &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; also &lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; at pc 0x400da0.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; at 0x400da0: file bomb.c, line 37.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;break-function-对指定函数打断点&#34;&gt;break function 对指定函数打断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; b main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; at 0x400da0: file bomb.c, line 37.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; b phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Breakpoint &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; at 0x400ee0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;删除断点包括禁用断点&#34;&gt;删除断点包括禁用断点&lt;/h2&gt;
&lt;h3 id=&#34;delete-删除所有断点&#34;&gt;delete 删除所有断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; delete 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Delete all breakpoints? &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;y or n&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; y
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;disable-breakpoint-禁用断点&#34;&gt;disable breakpoint 禁用断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b &lt;span class=&#34;c1&#34;&gt;#先看有哪些断点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Num     Type           Disp Enb Address            What
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;3&lt;/span&gt;       breakpoint     keep y   0x0000000000400da0 in main at bomb.c:37
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;       breakpoint     keep y   0x0000000000400ee0 &amp;lt;phase_1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; d &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;#禁用第三号断点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b &lt;span class=&#34;c1&#34;&gt;#再次查看断点信息发现已经没有第三号断点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Num     Type           Disp Enb Address            What
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;       breakpoint     keep y   0x0000000000400ee0 &amp;lt;phase_1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;clear-function-删除一个函数中所有的断点&#34;&gt;clear function 删除一个函数中所有的断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Num     Type           Disp Enb Address            What
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;       breakpoint     keep y   0x0000000000400ee0 &amp;lt;phase_1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; clear phase_1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;gdb&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; info b
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Deleted breakpoint &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; No breakpoints or watchpoints.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;启动与退出&#34;&gt;启动与退出&lt;/h2&gt;
&lt;h3 id=&#34;run-启动程序直到遇到断点&#34;&gt;run 启动程序直到遇到断点&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) run  
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;start-启动程序并在第一条代码处停下&#34;&gt;start 启动程序并在第一条代码处停下&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;x-配置-gdb-常用命令&#34;&gt;x 配置 gdb 常用命令&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gdb -q -x gdbinit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;//gdbinit
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;display/z $xs
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;display/z $x6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;display/z $x7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;set disassemble-next-line on
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;b _start
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;target remote: 34
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有了配置文件，就不用每次启动 gdb 时都要重新输入一遍调试命令。&lt;/p&gt;
&lt;h3 id=&#34;quit-退出调试&#34;&gt;quit 退出调试&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) quit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;调试命令&#34;&gt;调试命令&lt;/h2&gt;
&lt;h3 id=&#34;print-打印变量值&#34;&gt;print 打印变量值&lt;/h3&gt;
&lt;table&gt;
  &lt;thead&gt;
      &lt;tr&gt;
          &lt;th&gt;格式化字符 (/fmt)&lt;/th&gt;
          &lt;th&gt;说明&lt;/th&gt;
      &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
      &lt;tr&gt;
          &lt;td&gt;/x&lt;/td&gt;
          &lt;td&gt;以十六进制的形式打印出整数。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;/d&lt;/td&gt;
          &lt;td&gt;以有符号、十进制的形式打印出整数。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;/u&lt;/td&gt;
          &lt;td&gt;以无符号、十进制的形式打印出整数。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;/o&lt;/td&gt;
          &lt;td&gt;以八进制的形式打印出整数。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;/t&lt;/td&gt;
          &lt;td&gt;以二进制的形式打印出整数。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;/f&lt;/td&gt;
          &lt;td&gt;以浮点数的形式打印变量或表达式的值。&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
          &lt;td&gt;/c&lt;/td&gt;
          &lt;td&gt;以字符形式打印变量或表达式的值。&lt;/td&gt;
      &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p i       # 10进制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$5 = 3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p/x i     # 16进制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$6 = 0x3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) p/o i     # 8进制
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$7 = 03
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;打印地址值&#34;&gt;打印地址值&lt;/h3&gt;
&lt;p&gt;表示从内存地址 0x54320 读取内容，h 表示以双字节为单位，3 表示输出 3 个单位，u 表示按照十六进制显示。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) x/3uh 0x54320 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看当前程序栈的内容：x/10x $sp–&amp;gt;打印 stack 的前 10 个元素
查看当前程序栈的信息：info frame&amp;mdash;-list general info about the frame
查看当前程序栈的参数：info args—lists arguments to the function
查看当前程序栈的局部变量：info locals—list variables stored in the frame
查看当前寄存器的值：info registers(不包括浮点寄存器)&lt;/p&gt;
&lt;h3 id=&#34;ptype-打印变量类型&#34;&gt;ptype 打印变量类型&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) ptype i
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type = int
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) ptype array[i]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type = int
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) ptype array
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;type = int [12]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;display-跟踪显示变量&#34;&gt;display 跟踪显示变量&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;print&lt;/code&gt;命令可以打印出变量的值，但是只是一次性的。如果我们想要跟踪某个变量的变化，可以使用&lt;code&gt;display&lt;/code&gt;命令，每当程序在断点处停下，都会打印出跟踪的变量值。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) display 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;info display&lt;/code&gt;查看已跟踪的变量，&lt;code&gt;delete display&lt;/code&gt;取消跟踪显示变量。&lt;/p&gt;
&lt;h3 id=&#34;step-执行一行代码&#34;&gt;step 执行一行代码&lt;/h3&gt;
&lt;p&gt;执行一行代码，如果改行代码是函数，将进入函数内部。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;(gdb) s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;finish-跳出函数&#34;&gt;finish 跳出函数&lt;/h3&gt;
&lt;p&gt;如果通过&lt;code&gt;s&lt;/code&gt;单步调试进入到函数内部，想要跳出这个函数体，可以执行 &lt;code&gt;finish&lt;/code&gt;命令。如果想要跳出函数体必须要&lt;strong&gt;保证函数体内不能有有效断点&lt;/strong&gt;，否则无法跳出。&lt;/p&gt;
&lt;h3 id=&#34;next-执行一行代码&#34;&gt;next 执行一行代码&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;next&lt;/code&gt; 命令和 &lt;code&gt;step&lt;/code&gt; 命令功能是相似的，只是在使用 &lt;code&gt;next&lt;/code&gt; 调试程序的时候不会进入到函数体内部，&lt;code&gt;next&lt;/code&gt; 可以缩写为 &lt;code&gt;n&lt;/code&gt;。&lt;/p&gt;
&lt;h3 id=&#34;until-跳出循环体&#34;&gt;until 跳出循环体&lt;/h3&gt;
&lt;p&gt;通过 until 命令可以直接跳出某个循环体，这样就能提高调试效率了。如果想直接从循环体中跳出，必须要保证，&lt;strong&gt;要跳出的循环体内部不能有有效的断点&lt;/strong&gt;，&lt;strong&gt;必须要在循环体的开始 / 结束行执行该命令&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;layout-分割窗口边调试边看源码&#34;&gt;layout 分割窗口，边调试边看源码&lt;/h2&gt;
&lt;h3 id=&#34;layout-src&#34;&gt;layout src&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;layout-asm&#34;&gt;layout asm&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h3 id=&#34;layout-split&#34;&gt;layout split&lt;/h3&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;远程调试&#34;&gt;远程调试&lt;/h2&gt;
&lt;h3 id=&#34;-s--s&#34;&gt;&lt;code&gt;-s -S&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;-s&lt;/code&gt;启动&lt;code&gt;gdb server&lt;/code&gt;，默认端口号为 1234
&lt;code&gt;-S&lt;/code&gt;让程序在&lt;code&gt;_start&lt;/code&gt;处停下。&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="file-加载程序">file 加载程序</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> file bomb
</span></span><span class="line"><span class="cl">Reading symbols from bomb...
</span></span></code></pre></div><h2 id="set-args-带参数调试">set args 带参数调试</h2>
<p>有时候程序不是直接可以运行的，需要加上一些必要的参数。带上参数运行很容易，只要在程序名后加上相应参数即可，但是如何带上参数进行调试呢？这就需要<code>set args</code>命令。</p>
<p>比如在<code>BombLab</code>实验中，我们不可能一次解决所有<code>phase</code>，但是每次重新调试，已经解决的<code>phase</code>还要重新输入一次答案，这就很麻烦，好在这个实验的作者也考虑到了，他支持读取文本。我们可以把答案预先写入一个文本文件中，程序读取已经保存的答案即可跳过相应的<code>phase</code>。</p>
<p>假设我们把答案写入了<code>solutions.txt</code>文件中，首先，我们加载程序，然后通过<code>set args solutions.txt</code>设置运行参数。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> file bomb
</span></span><span class="line"><span class="cl">Reading symbols from bomb...
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> <span class="nb">set</span> args solutions.txt 
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> r
</span></span><span class="line"><span class="cl">Starting program: /home/dominic/learning-linux/bomb/bomb solutions.txt 
</span></span><span class="line"><span class="cl">Welcome to my fiendish little bomb. You have <span class="m">6</span> phases with
</span></span><span class="line"><span class="cl">which to blow yourself up. Have a nice day!
</span></span><span class="line"><span class="cl">Phase <span class="m">1</span> defused. How about the next one?
</span></span><span class="line"><span class="cl">That<span class="err">&#39;</span>s number 2.  Keep going!
</span></span></code></pre></div><h2 id="list-查看源码">list 查看源码</h2>
<h3 id="查看-10-行源码">查看 10 行源码</h3>
<p>每条命令显示 10 行代码</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> l
</span></span><span class="line"><span class="cl"><span class="m">23</span> <span class="c1">#include &lt;stdio.h&gt;</span>
</span></span><span class="line"><span class="cl"><span class="m">24</span> <span class="c1">#include &lt;stdlib.h&gt;</span>
</span></span><span class="line"><span class="cl"><span class="m">25</span> <span class="c1">#include &#34;support.h&#34;</span>
</span></span><span class="line"><span class="cl"><span class="m">26</span> <span class="c1">#include &#34;phases.h&#34;</span>
</span></span><span class="line"><span class="cl"><span class="m">27</span> 
</span></span><span class="line"><span class="cl"><span class="m">28</span> /* 
</span></span><span class="line"><span class="cl"><span class="m">29</span>  * Note to self: Remember to erase this file so my victims will have no
</span></span><span class="line"><span class="cl"><span class="m">30</span>  * idea what is going on, and so they will all blow up in a
</span></span><span class="line"><span class="cl"><span class="m">31</span>  * spectaculary fiendish explosion. -- Dr. Evil 
</span></span><span class="line"><span class="cl"><span class="m">32</span>  */
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> l
</span></span><span class="line"><span class="cl"><span class="m">33</span> 
</span></span><span class="line"><span class="cl"><span class="m">34</span> FILE *infile<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="m">35</span> 
</span></span><span class="line"><span class="cl"><span class="m">36</span> int main<span class="o">(</span>int argc, char *argv<span class="o">[])</span>
</span></span><span class="line"><span class="cl"><span class="m">37</span> <span class="o">{</span>
</span></span><span class="line"><span class="cl"><span class="m">38</span>     char *input<span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="m">39</span> 
</span></span><span class="line"><span class="cl"><span class="m">40</span>     /* Note to self: remember to port this bomb to Windows and put a 
</span></span><span class="line"><span class="cl"><span class="m">41</span>      * fantastic GUI on it. */
</span></span><span class="line"><span class="cl"><span class="m">42</span>
</span></span></code></pre></div><h3 id="set-list-num-设置默认显示代码行数">set list num 设置默认显示代码行数</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) set list 20   //默认显示20行代码
</span></span></code></pre></div><h3 id="list-linenumber-查看指定行代码">list linenumber 查看指定行代码</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) l 10  
</span></span><span class="line"><span class="cl">(gdb) l main.h : 10 //指定main.c文件中的第十行
</span></span></code></pre></div><h3 id="list-function-查看指定函数的代码">list function 查看指定函数的代码</h3>
<h2 id="break-打断点">break 打断点</h2>
<h3 id="break-linenum-对指定行打断点">break linenum 对指定行打断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> b <span class="m">36</span>
</span></span><span class="line"><span class="cl">Note: breakpoint <span class="m">1</span> also <span class="nb">set</span> at pc 0x400da0.
</span></span><span class="line"><span class="cl">Breakpoint <span class="m">2</span> at 0x400da0: file bomb.c, line 37.
</span></span></code></pre></div><h3 id="break-function-对指定函数打断点">break function 对指定函数打断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> b main
</span></span><span class="line"><span class="cl">Breakpoint <span class="m">3</span> at 0x400da0: file bomb.c, line 37.
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> b phase_1
</span></span><span class="line"><span class="cl">Breakpoint <span class="m">4</span> at 0x400ee0
</span></span></code></pre></div><h2 id="删除断点包括禁用断点">删除断点包括禁用断点</h2>
<h3 id="delete-删除所有断点">delete 删除所有断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> delete 
</span></span><span class="line"><span class="cl">Delete all breakpoints? <span class="o">(</span>y or n<span class="o">)</span> y
</span></span></code></pre></div><h3 id="disable-breakpoint-禁用断点">disable breakpoint 禁用断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b <span class="c1">#先看有哪些断点</span>
</span></span><span class="line"><span class="cl">Num     Type           Disp Enb Address            What
</span></span><span class="line"><span class="cl"><span class="m">3</span>       breakpoint     keep y   0x0000000000400da0 in main at bomb.c:37
</span></span><span class="line"><span class="cl"><span class="m">4</span>       breakpoint     keep y   0x0000000000400ee0 &lt;phase_1&gt;
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> d <span class="m">3</span> <span class="c1">#禁用第三号断点</span>
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b <span class="c1">#再次查看断点信息发现已经没有第三号断点</span>
</span></span><span class="line"><span class="cl">Num     Type           Disp Enb Address            What
</span></span><span class="line"><span class="cl"><span class="m">4</span>       breakpoint     keep y   0x0000000000400ee0 &lt;phase_1&gt;
</span></span></code></pre></div><h3 id="clear-function-删除一个函数中所有的断点">clear function 删除一个函数中所有的断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-shell" data-lang="shell"><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b
</span></span><span class="line"><span class="cl">Num     Type           Disp Enb Address            What
</span></span><span class="line"><span class="cl"><span class="m">4</span>       breakpoint     keep y   0x0000000000400ee0 &lt;phase_1&gt;
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> clear phase_1
</span></span><span class="line"><span class="cl"><span class="o">(</span>gdb<span class="o">)</span> info b
</span></span><span class="line"><span class="cl">Deleted breakpoint <span class="m">4</span> No breakpoints or watchpoints.
</span></span></code></pre></div><h2 id="启动与退出">启动与退出</h2>
<h3 id="run-启动程序直到遇到断点">run 启动程序直到遇到断点</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) run  
</span></span></code></pre></div><h3 id="start-启动程序并在第一条代码处停下">start 启动程序并在第一条代码处停下</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) start
</span></span></code></pre></div><h3 id="x-配置-gdb-常用命令">x 配置 gdb 常用命令</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">gdb -q -x gdbinit
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">//gdbinit
</span></span><span class="line"><span class="cl">display/z $xs
</span></span><span class="line"><span class="cl">display/z $x6
</span></span><span class="line"><span class="cl">display/z $x7
</span></span><span class="line"><span class="cl">set disassemble-next-line on
</span></span><span class="line"><span class="cl">b _start
</span></span><span class="line"><span class="cl">target remote: 34
</span></span></code></pre></div><p>有了配置文件，就不用每次启动 gdb 时都要重新输入一遍调试命令。</p>
<h3 id="quit-退出调试">quit 退出调试</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) quit
</span></span></code></pre></div><h2 id="调试命令">调试命令</h2>
<h3 id="print-打印变量值">print 打印变量值</h3>
<table>
  <thead>
      <tr>
          <th>格式化字符 (/fmt)</th>
          <th>说明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>/x</td>
          <td>以十六进制的形式打印出整数。</td>
      </tr>
      <tr>
          <td>/d</td>
          <td>以有符号、十进制的形式打印出整数。</td>
      </tr>
      <tr>
          <td>/u</td>
          <td>以无符号、十进制的形式打印出整数。</td>
      </tr>
      <tr>
          <td>/o</td>
          <td>以八进制的形式打印出整数。</td>
      </tr>
      <tr>
          <td>/t</td>
          <td>以二进制的形式打印出整数。</td>
      </tr>
      <tr>
          <td>/f</td>
          <td>以浮点数的形式打印变量或表达式的值。</td>
      </tr>
      <tr>
          <td>/c</td>
          <td>以字符形式打印变量或表达式的值。</td>
      </tr>
  </tbody>
</table>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) p i       # 10进制
</span></span><span class="line"><span class="cl">$5 = 3
</span></span><span class="line"><span class="cl">(gdb) p/x i     # 16进制
</span></span><span class="line"><span class="cl">$6 = 0x3
</span></span><span class="line"><span class="cl">(gdb) p/o i     # 8进制
</span></span><span class="line"><span class="cl">$7 = 03
</span></span></code></pre></div><h3 id="打印地址值">打印地址值</h3>
<p>表示从内存地址 0x54320 读取内容，h 表示以双字节为单位，3 表示输出 3 个单位，u 表示按照十六进制显示。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) x/3uh 0x54320 
</span></span></code></pre></div><p>查看当前程序栈的内容：x/10x $sp–&gt;打印 stack 的前 10 个元素
查看当前程序栈的信息：info frame&mdash;-list general info about the frame
查看当前程序栈的参数：info args—lists arguments to the function
查看当前程序栈的局部变量：info locals—list variables stored in the frame
查看当前寄存器的值：info registers(不包括浮点寄存器)</p>
<h3 id="ptype-打印变量类型">ptype 打印变量类型</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) ptype i
</span></span><span class="line"><span class="cl">type = int
</span></span><span class="line"><span class="cl">(gdb) ptype array[i]
</span></span><span class="line"><span class="cl">type = int
</span></span><span class="line"><span class="cl">(gdb) ptype array
</span></span><span class="line"><span class="cl">type = int [12]
</span></span></code></pre></div><h3 id="display-跟踪显示变量">display 跟踪显示变量</h3>
<p><code>print</code>命令可以打印出变量的值，但是只是一次性的。如果我们想要跟踪某个变量的变化，可以使用<code>display</code>命令，每当程序在断点处停下，都会打印出跟踪的变量值。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) display 
</span></span></code></pre></div><p><code>info display</code>查看已跟踪的变量，<code>delete display</code>取消跟踪显示变量。</p>
<h3 id="step-执行一行代码">step 执行一行代码</h3>
<p>执行一行代码，如果改行代码是函数，将进入函数内部。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">(gdb) s
</span></span></code></pre></div><h3 id="finish-跳出函数">finish 跳出函数</h3>
<p>如果通过<code>s</code>单步调试进入到函数内部，想要跳出这个函数体，可以执行 <code>finish</code>命令。如果想要跳出函数体必须要<strong>保证函数体内不能有有效断点</strong>，否则无法跳出。</p>
<h3 id="next-执行一行代码">next 执行一行代码</h3>
<p><code>next</code> 命令和 <code>step</code> 命令功能是相似的，只是在使用 <code>next</code> 调试程序的时候不会进入到函数体内部，<code>next</code> 可以缩写为 <code>n</code>。</p>
<h3 id="until-跳出循环体">until 跳出循环体</h3>
<p>通过 until 命令可以直接跳出某个循环体，这样就能提高调试效率了。如果想直接从循环体中跳出，必须要保证，<strong>要跳出的循环体内部不能有有效的断点</strong>，<strong>必须要在循环体的开始 / 结束行执行该命令</strong>。</p>
<h2 id="layout-分割窗口边调试边看源码">layout 分割窗口，边调试边看源码</h2>
<h3 id="layout-src">layout src</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153452.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="layout-asm">layout asm</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153520.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h3 id="layout-split">layout split</h3>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210830153555.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="远程调试">远程调试</h2>
<h3 id="-s--s"><code>-s -S</code></h3>
<p><code>-s</code>启动<code>gdb server</code>，默认端口号为 1234
<code>-S</code>让程序在<code>_start</code>处停下。</p>
]]></content:encoded>
    </item>
    <item>
      <title>VSCode 调试 RISC-V 程序</title>
      <link>https://lifeislife.cn/posts/vscode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/</link>
      <pubDate>Mon, 23 Aug 2021 15:51:51 +0000</pubDate>
      <guid>https://lifeislife.cn/posts/vscode%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F/</guid>
      <description>&lt;h2 id=&#34;前提&#34;&gt;前提&lt;/h2&gt;
&lt;p&gt;本文主要涉及 VSCode 的相关配置，编译及调试工具需要提前安装好。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;已经安装好&lt;code&gt;riscv-toolchain&lt;/code&gt;，包括&lt;code&gt;riscv64-unknown-elf-gcc&lt;/code&gt;，&lt;code&gt;riscv64-unknown-elf-gdb&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;已经安装好&lt;code&gt;qemu&lt;/code&gt;，包括&lt;code&gt;riscv32-softmmu,riscv32-linux-user,riscv64-softmmu,riscv64-linux-user&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;已经安装好&lt;code&gt;g++&lt;/code&gt;,&lt;code&gt;gdb&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;调试流程简介&#34;&gt;调试流程简介&lt;/h2&gt;
&lt;p&gt;对于我这样的新手，要调试一个项目源码最怕的就是开始，也就是怎么能把项目跑起来。&lt;/p&gt;
&lt;p&gt;我们以一个简单的&lt;code&gt;test&lt;/code&gt;项目，看看在 VSCode 里怎么跑起来。&lt;/p&gt;
&lt;p&gt;拿到源码后，将其以文件夹形式，加入到 VSCode 中，&lt;code&gt;文件 - 打开文件夹 - 选择 test 项目文件夹&lt;/code&gt;。项目就会在 VSCode 中打开，但是此时我们还无法编译运行，我们需要在 VSCode 上
构建出一个 C 语言的编译与调试环境。&lt;/p&gt;
&lt;p&gt;首先得安装一个插件&lt;code&gt;C/C++&lt;/code&gt;，打开插件中心&lt;code&gt;Ctrl+Shit+X&lt;/code&gt;，搜索，安装。&lt;/p&gt;
&lt;p&gt;然后输入&lt;code&gt;F5&lt;/code&gt;，会弹出对话框，选择&lt;code&gt;C++(GDB)&lt;/code&gt;，继续选择&lt;code&gt;g++&lt;/code&gt;。VSCode 会自动创建&lt;code&gt;.vscode&lt;/code&gt;文件夹，已经两个文件&lt;code&gt;launch.json&lt;/code&gt;和&lt;code&gt;tasks.json&lt;/code&gt;。


&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;launch.json&lt;/code&gt;用来配置调试环境，&lt;code&gt;tasks.json&lt;/code&gt;主要用来配置编译环境，当然也可以配置其他任务。&lt;code&gt;task.json&lt;/code&gt;里配置的每个任务其实就相当于多开一个控制台。&lt;/p&gt;
&lt;h2 id=&#34;配置tasksjson&#34;&gt;配置&lt;code&gt;tasks.json&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;因为我们先要编译源码，生成&lt;code&gt;.out&lt;/code&gt;或者&lt;code&gt;.exe&lt;/code&gt;文件，才能调试，所以先进行编译任务配置。&lt;/p&gt;
&lt;p&gt;自动生成的文件是个配置模板，我们可以根据自己的实际情况进行配置，也有一部分可以保持默认。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// tasks.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    // https://code.visualstudio.com/docs/editor/tasks
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;2.0.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;tasks&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             // 任务的名字，注意是大小写区分的
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             //会在launch中调用这个名字
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;C/C++: g++ build active file&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             // 任务执行的是shell
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             // 命令是g++
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;g++&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;             //g++ 后面带的参数
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;-Wall&amp;#39;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-g&amp;#34;,           // 生成调试信息，否则无法进入断点
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;-std=c++17&amp;#39;&amp;#34;,     //使用c++17标准编译
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;${file}&amp;#39;&amp;#34;,        //当前文件名
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-o&amp;#34;,               //对象名，不进行编译优化
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;&amp;#39;${fileBasenameNoExtension}.exe&amp;#39;&amp;#34;,  //当前文件名（去掉扩展名）
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果项目是通过 Makefile 编译的，那就更加简单，只需要配置一个任务即可。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;version&amp;#34;: &amp;#34;2.0.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &amp;#34;tasks&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       //任务的名字方便执行
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;label&amp;#34;: &amp;#34;Make Project&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;command&amp;#34;: &amp;#34;make&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &amp;#34;args&amp;#34;:[
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          //8线程编译
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &amp;#34;-j8&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行该任务时就会执行&lt;code&gt;make&lt;/code&gt;命令进行编译。&lt;/p&gt;
&lt;h2 id=&#34;配置launchjson&#34;&gt;配置&lt;code&gt;launch.json&lt;/code&gt;&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// launch.json
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;0.2.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;configurations&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //调试任务的名字
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;name&amp;#34;: &amp;#34;g++ - Build and debug active file&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //在launch之前运行的任务名，这个名字一定要跟tasks.json中的任务名字大小写一致
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;preLaunchTask&amp;#34;: &amp;#34;C/C++: g++ build active file&amp;#34;,  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;cppdbg&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;request&amp;#34;: &amp;#34;launch&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //需要运行的是当前打开文件的目录中，
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            //名字和当前文件相同，但扩展名为exe的程序
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;program&amp;#34;: &amp;#34;${fileDirname}/${fileBasenameNoExtension}.exe&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 选为true则会在打开控制台后停滞，暂时不执行程序
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;stopAtEntry&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 当前工作路径：当前文件所在的工作空间
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;cwd&amp;#34;: &amp;#34;${workspaceFolder}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;environment&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 是否使用外部控制台
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;externalConsole&amp;#34;: false,  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;MIMode&amp;#34;: &amp;#34;gdb&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;setupCommands&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;description&amp;#34;: &amp;#34;Enable pretty-printing for gdb&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;text&amp;#34;: &amp;#34;-enable-pretty-printing&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;ignoreFailures&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;运行&#34;&gt;运行&lt;/h2&gt;
&lt;p&gt;经过以上配置后，我们打开&lt;code&gt;main.cpp&lt;/code&gt;文件，在&lt;code&gt;cout&lt;/code&gt;处打一个断点，按&lt;code&gt;F5&lt;/code&gt;，即可编译，运行，调试。一定要打开&lt;code&gt;main.cpp&lt;/code&gt;文件，不能随便打开文件就开始哦。因为我们在配置时使用了一些预定义，比如&lt;code&gt;${file}&lt;/code&gt;表示当前文件，所以只有打开需要调试的文件才能开始。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;程序将会在&lt;code&gt;cout&lt;/code&gt;语句停下来。&lt;/p&gt;
&lt;p&gt;我们可以注意一下界面下方的控制台，可以更直观了解&lt;code&gt;launch.jason&lt;/code&gt;和&lt;code&gt;tasks.jason&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;右边的框，就是我们在&lt;code&gt;tasks.jason&lt;/code&gt;中配置的任务，左边的框就是我们在&lt;code&gt;tasks.jason&lt;/code&gt;中&lt;code&gt;command&lt;/code&gt;以及&lt;code&gt;args&lt;/code&gt;的内容，他就是帮我们提前写好编译的选项。然后在 shell 中运行。&lt;/p&gt;
&lt;h2 id=&#34;编译调试-risc-v-程序&#34;&gt;编译调试 RISC-V 程序&lt;/h2&gt;
&lt;p&gt;了解以上这些，就可以按需配置所需的环境了。我们还是从&lt;code&gt;tasks.jason&lt;/code&gt;开始。因为开发用的电脑是&lt;code&gt;x86&lt;/code&gt;的，所以先要编译出&lt;code&gt;riscv&lt;/code&gt;的程序，再用模拟器模拟出&lt;code&gt;rsicv&lt;/code&gt;的环境，然后在模拟的环境中运行程序，最后才能开始调试。&lt;/p&gt;
&lt;p&gt;假设已经安装好开头所提到的工具。首先配置&lt;code&gt;tasks.jason&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;2.0.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;tasks&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 编译当前代码
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;C/C++(RISCV): Build active file&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 编译器的位置
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;/opt/riscv/bin/riscv64-unknown-elf-g++&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-Wall&amp;#34;, // 开启所有警告
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-g&amp;#34;, // 生成调试信息s
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;${file}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-o&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34; // 我选择将可执行文件放在debug目录下
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 当前工作路径：执行当前命令时所在的路径
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;options&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;cwd&amp;#34;: &amp;#34;${workspaceFolder}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;problemMatcher&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;$gcc&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 启动qemu供调试器连接
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;Run Qemu Server(RISCV)&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;dependsOn&amp;#34;: &amp;#34;C/C++(RISCV): Build active file&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;qemu-system-riscv64&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;-g&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;65500&amp;#34;, // gdb端口，自己定义
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        },
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 有时候qemu有可能没法退出，故编写一个任务用于强行结束qemu进程
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;shell&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;label&amp;#34;: &amp;#34;Kill Qemu Server(RISCV)&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;command&amp;#34;: &amp;#34;ps -C qemu-riscv64 --no-headers | cut -d \\  -f 1 | xargs kill -9&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;tasks.jason&lt;/code&gt;是可以配置多个任务的，第一个任务用来编译成&lt;code&gt;riscv&lt;/code&gt;架构下的程序，第二个任务用来启动 qemu，让程序在 qemu 上运行起来。&lt;/p&gt;
&lt;p&gt;第一个任务中，&lt;code&gt;command&lt;/code&gt;就是配置编译器&lt;code&gt;riscv64-unkonown-elf-gcc&lt;/code&gt;的属性，第二个任务中，&lt;code&gt;command&lt;/code&gt;是配置 qemu 模拟器&lt;code&gt;qemu-system-riscv32&lt;/code&gt;的属性。第三个任务中，用来配置结束 qemu 模拟器的命令。&lt;/p&gt;
&lt;p&gt;接下来配置&lt;code&gt;launch.jason&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;version&amp;#34;: &amp;#34;0.2.0&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &amp;#34;configurations&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        { 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;name&amp;#34;: &amp;#34;C/C++(RISCV) - Debug Active File&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;type&amp;#34;: &amp;#34;cppdbg&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;request&amp;#34;: &amp;#34;launch&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;program&amp;#34;: &amp;#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;args&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;stopAtEntry&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;cwd&amp;#34;: &amp;#34;${workspaceFolder}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;environment&amp;#34;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;externalConsole&amp;#34;: false,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;MIMode&amp;#34;: &amp;#34;gdb&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;setupCommands&amp;#34;: [
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;description&amp;#34;: &amp;#34;为 gdb 启用整齐打印&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;text&amp;#34;: &amp;#34;-enable-pretty-printing&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                    &amp;#34;ignoreFailures&amp;#34;: true
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            ],
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // RISC-V工具链中的gdb
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;miDebuggerPath&amp;#34;: &amp;#34;/opt/riscv/bin/riscv64-unknown-elf-gdb&amp;#34;, 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            // 这里需要与task.json中定义的端口一致
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &amp;#34;miDebuggerServerAddress&amp;#34;: &amp;#34;localhost:65500&amp;#34; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    ]
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们在配置&lt;code&gt;x86&lt;/code&gt;下的调试环境时，&lt;code&gt;launch.jason&lt;/code&gt;中有个&lt;code&gt;&amp;quot;preLaunchTask&amp;quot;: &amp;quot;C/C++: g++ build active file&amp;quot;&lt;/code&gt;，属性，这个属性的目的是在启动调试之前，先执行任务名字为&lt;code&gt;&amp;quot;C/C++: g++ build active file&amp;quot;&lt;/code&gt;任务，也是就编译的任务。&lt;/p&gt;
&lt;p&gt;因为启动 qemu 会导致阻塞，所以这里没有加&lt;code&gt;preLaunchTask&lt;/code&gt;，在启动调试之前，先把 qemu 运行起来。输入&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;，打开 VSCode 命令行。输入&lt;code&gt;Run Task&lt;/code&gt;，&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;p&gt;点击第一个，选择任务，我们可以看到出现的三个任务就是我们在&lt;code&gt;tasks.jason&lt;/code&gt;中配置的三个任务。选择第一个 Build，编译出程序，再重复操作，选择第三个执行 QEMU 任务。&lt;/p&gt;
&lt;p&gt;

&lt;!DOCTYPE html&gt;
&lt;html lang=&#34;en&#34;&gt;
&lt;head&gt;
    &lt;meta charset=&#34;UTF-8&#34;&gt;
    &lt;meta name=&#34;viewport&#34; content=&#34;width=device-width, initial-scale=1.0&#34;&gt;
    &lt;title&gt;Responsive Image&lt;/title&gt;
    &lt;style&gt;
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    
    &lt;div class=&#34;post-img-view&#34;&gt;
        &lt;a data-fancybox=&#34;gallery&#34; href=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png&#34;&gt;
            &lt;img class=&#34;responsive-image&#34; src=&#34;https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png&#34; alt=&#34;&#34;  style=&#34;margin: 0 auto;&#34;/&gt;
        &lt;/a&gt;
    &lt;/div&gt;
    

    &lt;script&gt;
        document.addEventListener(&#34;DOMContentLoaded&#34;, function() {
            var images = document.querySelectorAll(&#34;.responsive-image&#34;);
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + &#34;px&#34;;
            });
        });
    &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;&lt;/p&gt;
&lt;h2 id=&#34;预定义变量&#34;&gt;预定义变量&lt;/h2&gt;
&lt;p&gt;&lt;a href=&#34;https://code.visualstudio.com/docs/editor/variables-reference#_predefined-variables&#34;&gt;官网&lt;/a&gt;&lt;/p&gt;
</description>
      <content:encoded><![CDATA[<h2 id="前提">前提</h2>
<p>本文主要涉及 VSCode 的相关配置，编译及调试工具需要提前安装好。</p>
<ul>
<li>已经安装好<code>riscv-toolchain</code>，包括<code>riscv64-unknown-elf-gcc</code>，<code>riscv64-unknown-elf-gdb</code></li>
<li>已经安装好<code>qemu</code>，包括<code>riscv32-softmmu,riscv32-linux-user,riscv64-softmmu,riscv64-linux-user</code></li>
<li>已经安装好<code>g++</code>,<code>gdb</code></li>
</ul>
<h2 id="调试流程简介">调试流程简介</h2>
<p>对于我这样的新手，要调试一个项目源码最怕的就是开始，也就是怎么能把项目跑起来。</p>
<p>我们以一个简单的<code>test</code>项目，看看在 VSCode 里怎么跑起来。</p>
<p>拿到源码后，将其以文件夹形式，加入到 VSCode 中，<code>文件 - 打开文件夹 - 选择 test 项目文件夹</code>。项目就会在 VSCode 中打开，但是此时我们还无法编译运行，我们需要在 VSCode 上
构建出一个 C 语言的编译与调试环境。</p>
<p>首先得安装一个插件<code>C/C++</code>，打开插件中心<code>Ctrl+Shit+X</code>，搜索，安装。</p>
<p>然后输入<code>F5</code>，会弹出对话框，选择<code>C++(GDB)</code>，继续选择<code>g++</code>。VSCode 会自动创建<code>.vscode</code>文件夹，已经两个文件<code>launch.json</code>和<code>tasks.json</code>。


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823193157.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p><code>launch.json</code>用来配置调试环境，<code>tasks.json</code>主要用来配置编译环境，当然也可以配置其他任务。<code>task.json</code>里配置的每个任务其实就相当于多开一个控制台。</p>
<h2 id="配置tasksjson">配置<code>tasks.json</code></h2>
<p>因为我们先要编译源码，生成<code>.out</code>或者<code>.exe</code>文件，才能调试，所以先进行编译任务配置。</p>
<p>自动生成的文件是个配置模板，我们可以根据自己的实际情况进行配置，也有一部分可以保持默认。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">// tasks.json
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    // https://code.visualstudio.com/docs/editor/tasks
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;2.0.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;tasks&#34;: [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">             // 任务的名字，注意是大小写区分的
</span></span><span class="line"><span class="cl">             //会在launch中调用这个名字
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;C/C++: g++ build active file&#34;, 
</span></span><span class="line"><span class="cl">             // 任务执行的是shell
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;, 
</span></span><span class="line"><span class="cl">             // 命令是g++
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;g++&#34;, 
</span></span><span class="line"><span class="cl">             //g++ 后面带的参数
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [
</span></span><span class="line"><span class="cl">                &#34;&#39;-Wall&#39;&#34;,
</span></span><span class="line"><span class="cl">                &#34;-g&#34;,           // 生成调试信息，否则无法进入断点
</span></span><span class="line"><span class="cl">                &#34;&#39;-std=c++17&#39;&#34;,     //使用c++17标准编译
</span></span><span class="line"><span class="cl">                &#34;&#39;${file}&#39;&#34;,        //当前文件名
</span></span><span class="line"><span class="cl">                &#34;-o&#34;,               //对象名，不进行编译优化
</span></span><span class="line"><span class="cl">                &#34;&#39;${fileBasenameNoExtension}.exe&#39;&#34;,  //当前文件名（去掉扩展名）
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>如果项目是通过 Makefile 编译的，那就更加简单，只需要配置一个任务即可。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">  &#34;version&#34;: &#34;2.0.0&#34;,
</span></span><span class="line"><span class="cl">  &#34;tasks&#34;: [
</span></span><span class="line"><span class="cl">    {
</span></span><span class="line"><span class="cl">       //任务的名字方便执行
</span></span><span class="line"><span class="cl">      &#34;label&#34;: &#34;Make Project&#34;,
</span></span><span class="line"><span class="cl">      &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">      &#34;command&#34;: &#34;make&#34;,
</span></span><span class="line"><span class="cl">      &#34;args&#34;:[
</span></span><span class="line"><span class="cl">          //8线程编译
</span></span><span class="line"><span class="cl">          &#34;-j8&#34;,
</span></span><span class="line"><span class="cl">      ],
</span></span><span class="line"><span class="cl">    },
</span></span><span class="line"><span class="cl">  ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>运行该任务时就会执行<code>make</code>命令进行编译。</p>
<h2 id="配置launchjson">配置<code>launch.json</code></h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">// launch.json
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;0.2.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;configurations&#34;: [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            //调试任务的名字
</span></span><span class="line"><span class="cl">            &#34;name&#34;: &#34;g++ - Build and debug active file&#34;, 
</span></span><span class="line"><span class="cl">            //在launch之前运行的任务名，这个名字一定要跟tasks.json中的任务名字大小写一致
</span></span><span class="line"><span class="cl">            &#34;preLaunchTask&#34;: &#34;C/C++: g++ build active file&#34;,  
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;cppdbg&#34;,
</span></span><span class="line"><span class="cl">            &#34;request&#34;: &#34;launch&#34;,
</span></span><span class="line"><span class="cl">            //需要运行的是当前打开文件的目录中，
</span></span><span class="line"><span class="cl">            //名字和当前文件相同，但扩展名为exe的程序
</span></span><span class="line"><span class="cl">            &#34;program&#34;: &#34;${fileDirname}/${fileBasenameNoExtension}.exe&#34;, 
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [],
</span></span><span class="line"><span class="cl">            // 选为true则会在打开控制台后停滞，暂时不执行程序
</span></span><span class="line"><span class="cl">            &#34;stopAtEntry&#34;: false,
</span></span><span class="line"><span class="cl">            // 当前工作路径：当前文件所在的工作空间
</span></span><span class="line"><span class="cl">            &#34;cwd&#34;: &#34;${workspaceFolder}&#34;,
</span></span><span class="line"><span class="cl">            &#34;environment&#34;: [],
</span></span><span class="line"><span class="cl">            // 是否使用外部控制台
</span></span><span class="line"><span class="cl">            &#34;externalConsole&#34;: false,  
</span></span><span class="line"><span class="cl">            &#34;MIMode&#34;: &#34;gdb&#34;,
</span></span><span class="line"><span class="cl">            &#34;setupCommands&#34;: [
</span></span><span class="line"><span class="cl">                {
</span></span><span class="line"><span class="cl">                    &#34;description&#34;: &#34;Enable pretty-printing for gdb&#34;,
</span></span><span class="line"><span class="cl">                    &#34;text&#34;: &#34;-enable-pretty-printing&#34;,
</span></span><span class="line"><span class="cl">                    &#34;ignoreFailures&#34;: true
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">            ]
</span></span><span class="line"><span class="cl">        }]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><h2 id="运行">运行</h2>
<p>经过以上配置后，我们打开<code>main.cpp</code>文件，在<code>cout</code>处打一个断点，按<code>F5</code>，即可编译，运行，调试。一定要打开<code>main.cpp</code>文件，不能随便打开文件就开始哦。因为我们在配置时使用了一些预定义，比如<code>${file}</code>表示当前文件，所以只有打开需要调试的文件才能开始。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823201621.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>程序将会在<code>cout</code>语句停下来。</p>
<p>我们可以注意一下界面下方的控制台，可以更直观了解<code>launch.jason</code>和<code>tasks.jason</code>。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210823202012.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>右边的框，就是我们在<code>tasks.jason</code>中配置的任务，左边的框就是我们在<code>tasks.jason</code>中<code>command</code>以及<code>args</code>的内容，他就是帮我们提前写好编译的选项。然后在 shell 中运行。</p>
<h2 id="编译调试-risc-v-程序">编译调试 RISC-V 程序</h2>
<p>了解以上这些，就可以按需配置所需的环境了。我们还是从<code>tasks.jason</code>开始。因为开发用的电脑是<code>x86</code>的，所以先要编译出<code>riscv</code>的程序，再用模拟器模拟出<code>rsicv</code>的环境，然后在模拟的环境中运行程序，最后才能开始调试。</p>
<p>假设已经安装好开头所提到的工具。首先配置<code>tasks.jason</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;2.0.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;tasks&#34;: [
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            // 编译当前代码
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;C/C++(RISCV): Build active file&#34;,
</span></span><span class="line"><span class="cl">            // 编译器的位置
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;/opt/riscv/bin/riscv64-unknown-elf-g++&#34;,
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [
</span></span><span class="line"><span class="cl">                &#34;-Wall&#34;, // 开启所有警告
</span></span><span class="line"><span class="cl">                &#34;-g&#34;, // 生成调试信息s
</span></span><span class="line"><span class="cl">                &#34;${file}&#34;,
</span></span><span class="line"><span class="cl">                &#34;-o&#34;,
</span></span><span class="line"><span class="cl">                &#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34; // 我选择将可执行文件放在debug目录下
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">            // 当前工作路径：执行当前命令时所在的路径
</span></span><span class="line"><span class="cl">            &#34;options&#34;: {
</span></span><span class="line"><span class="cl">                &#34;cwd&#34;: &#34;${workspaceFolder}&#34;
</span></span><span class="line"><span class="cl">            },
</span></span><span class="line"><span class="cl">            &#34;problemMatcher&#34;: [
</span></span><span class="line"><span class="cl">                &#34;$gcc&#34;
</span></span><span class="line"><span class="cl">            ]
</span></span><span class="line"><span class="cl">        },
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            // 启动qemu供调试器连接
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;Run Qemu Server(RISCV)&#34;,
</span></span><span class="line"><span class="cl">            &#34;dependsOn&#34;: &#34;C/C++(RISCV): Build active file&#34;,
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;qemu-system-riscv64&#34;,
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [
</span></span><span class="line"><span class="cl">                &#34;-g&#34;,
</span></span><span class="line"><span class="cl">                &#34;65500&#34;, // gdb端口，自己定义
</span></span><span class="line"><span class="cl">                &#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34;
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">        },
</span></span><span class="line"><span class="cl">        {
</span></span><span class="line"><span class="cl">            // 有时候qemu有可能没法退出，故编写一个任务用于强行结束qemu进程
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;shell&#34;,
</span></span><span class="line"><span class="cl">            &#34;label&#34;: &#34;Kill Qemu Server(RISCV)&#34;,
</span></span><span class="line"><span class="cl">            &#34;command&#34;: &#34;ps -C qemu-riscv64 --no-headers | cut -d \\  -f 1 | xargs kill -9&#34;,
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p><code>tasks.jason</code>是可以配置多个任务的，第一个任务用来编译成<code>riscv</code>架构下的程序，第二个任务用来启动 qemu，让程序在 qemu 上运行起来。</p>
<p>第一个任务中，<code>command</code>就是配置编译器<code>riscv64-unkonown-elf-gcc</code>的属性，第二个任务中，<code>command</code>是配置 qemu 模拟器<code>qemu-system-riscv32</code>的属性。第三个任务中，用来配置结束 qemu 模拟器的命令。</p>
<p>接下来配置<code>launch.jason</code>：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">    &#34;version&#34;: &#34;0.2.0&#34;,
</span></span><span class="line"><span class="cl">    &#34;configurations&#34;: [
</span></span><span class="line"><span class="cl">        { 
</span></span><span class="line"><span class="cl">            &#34;name&#34;: &#34;C/C++(RISCV) - Debug Active File&#34;,
</span></span><span class="line"><span class="cl">            &#34;type&#34;: &#34;cppdbg&#34;,
</span></span><span class="line"><span class="cl">            &#34;request&#34;: &#34;launch&#34;,
</span></span><span class="line"><span class="cl">            &#34;program&#34;: &#34;${workspaceFolder}/debug/${fileBasenameNoExtension}&#34;,
</span></span><span class="line"><span class="cl">            &#34;args&#34;: [],
</span></span><span class="line"><span class="cl">            &#34;stopAtEntry&#34;: false,
</span></span><span class="line"><span class="cl">            &#34;cwd&#34;: &#34;${workspaceFolder}&#34;,
</span></span><span class="line"><span class="cl">            &#34;environment&#34;: [],
</span></span><span class="line"><span class="cl">            &#34;externalConsole&#34;: false,
</span></span><span class="line"><span class="cl">            &#34;MIMode&#34;: &#34;gdb&#34;,
</span></span><span class="line"><span class="cl">            &#34;setupCommands&#34;: [
</span></span><span class="line"><span class="cl">                {
</span></span><span class="line"><span class="cl">                    &#34;description&#34;: &#34;为 gdb 启用整齐打印&#34;,
</span></span><span class="line"><span class="cl">                    &#34;text&#34;: &#34;-enable-pretty-printing&#34;,
</span></span><span class="line"><span class="cl">                    &#34;ignoreFailures&#34;: true
</span></span><span class="line"><span class="cl">                }
</span></span><span class="line"><span class="cl">            ],
</span></span><span class="line"><span class="cl">            // RISC-V工具链中的gdb
</span></span><span class="line"><span class="cl">            &#34;miDebuggerPath&#34;: &#34;/opt/riscv/bin/riscv64-unknown-elf-gdb&#34;, 
</span></span><span class="line"><span class="cl">            // 这里需要与task.json中定义的端口一致
</span></span><span class="line"><span class="cl">            &#34;miDebuggerServerAddress&#34;: &#34;localhost:65500&#34; 
</span></span><span class="line"><span class="cl">        }
</span></span><span class="line"><span class="cl">    ]
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>我们在配置<code>x86</code>下的调试环境时，<code>launch.jason</code>中有个<code>&quot;preLaunchTask&quot;: &quot;C/C++: g++ build active file&quot;</code>，属性，这个属性的目的是在启动调试之前，先执行任务名字为<code>&quot;C/C++: g++ build active file&quot;</code>任务，也是就编译的任务。</p>
<p>因为启动 qemu 会导致阻塞，所以这里没有加<code>preLaunchTask</code>，在启动调试之前，先把 qemu 运行起来。输入<code>Ctrl+Shift+P</code>，打开 VSCode 命令行。输入<code>Run Task</code>，</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094556.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<p>点击第一个，选择任务，我们可以看到出现的三个任务就是我们在<code>tasks.jason</code>中配置的三个任务。选择第一个 Build，编译出程序，再重复操作，选择第三个执行 QEMU 任务。</p>
<p>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Responsive Image</title>
    <style>
        .post-img-view {
            text-align: center;
        }
        .responsive-image {
            display: block;
            margin: 0 auto;
        }
    </style>
</head>
<body>
    
    <div class="post-img-view">
        <a data-fancybox="gallery" href="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png">
            <img class="responsive-image" src="https://picbed-1311007548.cos.ap-shanghai.myqcloud.com/markdown_picbed/img/20210824094609.png" alt=""  style="margin: 0 auto;"/>
        </a>
    </div>
    

    <script>
        document.addEventListener("DOMContentLoaded", function() {
            var images = document.querySelectorAll(".responsive-image");
            var maxHeight = window.innerHeight / 3;
            images.forEach(function(image) {
                image.style.maxHeight = maxHeight + "px";
            });
        });
    </script>
</body>
</html></p>
<h2 id="预定义变量">预定义变量</h2>
<p><a href="https://code.visualstudio.com/docs/editor/variables-reference#_predefined-variables">官网</a></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
