精华内容
下载资源
问答
  • 在汇编程序调试中遇到的错误
    2020-04-01 21:08:36

    debug

    debug在程序的调试过程中有很大的作用,可以帮助程序员更加快速地解决问题,因此一定要熟练掌握各种命令。

    • R命令——查看、改变CPU寄存器的内容
      格式:r 查看所有寄存器的内容;r 寄存器名 修改寄存器内容

    • D命令——查看内存中的内容
      格式:d 段地址:偏移地址d 段地址:起始偏移地址 结尾偏移地址

    • E命令——改写内存中的内容
      格式:e 起始地址 数据 数据 数据… 或者采用提问的方式一个一个的改写内存中的内容 也可以用e命令像内存中写入字符字符串

    • U命令——将内存中的机器指令翻译成汇编指令
      显示输出分为3部分,每一条机器指令的地址、机器指令、机器指令所对应的汇编指令

    • T命令——执行一条机器指令
      debug中单步执行一条指令 其实是一号中断 标志寄存器TF位为一
      注意,使用T命令执行mov ss,ax时,指向栈顶的指令会自动执行,原因是防止栈顶指向错误的地方

    • A命令——以汇编指令的格式在内存中写入一条机器指令
      比e命令更为方便地写入汇编指令

    • P命令
      P命令可以用来执行int 21h指令loop指令

    • G命令
      g命令可以在debug中将所有指令执行完毕;也可以执行一部分指令,格式:
      g 偏移地址

    debug对于程序的调试极为重要,遇到问题不要想着投机取巧,而要一步一步跟踪执行,才能发现问题所在。注意在编写一号中断时,因为单步执行需要一号中断,所以会出现问题,这时在debug中调试时可以先将中断处理程序放入其他地方,比如7ch处,这样就可以使用T命令跟踪调试了。

    DOS中的命令

    可以用cls来清屏

    更多相关内容
  • 2.熟悉PC机上编辑、汇编、连接、调试和运行汇编语言程序的过程。 二.实验内容 一个汇编语言程序从写出到最终执行的简要过程如下: 1) 编辑 可以用任意的文本编辑器来编辑源程序,只要最终将其存储为纯文本文件...

    一.实验目的
    1.熟练掌握编写汇编语言原程序的基本框架
    2.熟悉在PC机上编辑、汇编、连接、调试和运行汇编语言程序的过程。
    二.实验内容
    一个汇编语言程序从写出到最终执行的简要过程如下:
    1) 编辑
    可以用任意的文本编辑器来编辑源程序,只要最终将其存储为纯文本文件即可。一般保存为*.asm文件。
    2) 编译
    上机过程中,我们采用微软的masm5.0汇编编译器,文件名为masm.exe。我们的编译器在C:\masm5目录下,可以按照下面的过程来进行源程序的编译,以C:\1.asm为例:
    进入DOS方式,进入C:\masm5目录,运行masm.exe,首先显示一些版本信息,然后提示输入将要被编译的源程序文件名。在输入源程序文件名时一定要指明路径,如果文件在当前路径下,只要输入文件名就可以,否则要输入全路径。在此,我们输入C:\1.asm.
    输入源程序文件名后,程序继续提示我们输入要编译出的目标文件名,因为我们已经输入了源程序文件名为1.asm,则编译程序默认要输出的目标文件名为1.obj,所以我们可以不必另行指定文件名,直接按回车,编译程序将在当前目录下,生出1.obj文件。我们也可以指定生成的目标文件所在的目录,如想在“C:\windows\desktop”下生成目标文件1.obj,则可以输入“C:\windows\desktop\1”
    确定了目标文件名称后,编译程序提示输入列表文件名称和交叉引用文件名称,这些时编译器将源程序编译为目标文件过程中产生的中间结果,我们直接按回车键忽略。
    对源程序编译结束,编译器输出的最后两行告诉我们源程序是否有警告错误和必须要改正的错误。
    3) 链接
    对源程序进行编译得到目标文件后,需要对目标文件进行链接得到可执行文件。
    我们使用微软的Overlay Linker3.6连接器,文件名为link.exe,假设连接器在C:\masm5目录下,我们按照下面的过程来进行程序的链接,以C:\masm5\1.obj为例
    进入DOS方式,进入C:\masm5目录,运行link.exe,首先显示一些版本信息,然后提示输入将要被连接的目标文件名。此处我们输入”1”,按回车.程序继续提示我们输入要生成的可执行文件的名称,这是我们对一个程序进行连接要得到的最终结果。这里我们不必另行指定文件名,直接按回车,链接程序将在当前目录下,生成1.exe文件。
    确定了可执行文件的名称后,连接程序提示输入映像文件的名称和库文件的连接,我们直接按回车键忽略即可。
    最后对目标文件的连接结束,连接程序输出的最后一行告诉我们源程序是否有错误。如果尽出现一个警告错误:“没有栈段”,我们可以不理会。
    4) 执行和调试
    将生成的可执行文件执行:C:\masm5>1.exe,看不到任何结果,因为我们的程序没有向显示器输出信息。
    为了观察程序的运行过程,使用Debug的相关命令来单步执行程序,查看每一条指令的运行结果。
    进入C:\masm5后,我们输入“Debug 1.exe”,按Enter键,Debug将程序从1.exe中加载到内存,进行相关的初始化后设置CS:IP指向程序的入口。使用R命令查看各个寄存器的设置情况,使用U命令来查看我们写入的指令,使用T命令单步执行程序中的每一条指令,到达int 21,使用P命令执行,执行后,显示“Program terminated normally”,返回到Debug,表示程序正常结束。
    注意:在DOS中运行程序时,是Command将程序加载到内存,所以程序运行结束后返回到command中,而在这里是debug将程序加载到内存,所以程序运行结束后返回到debug中。
    三.实验任务

    1. 将下面的程序保存为t1.asm文件,生成可执行文件t1.exe;
      assume cs:codesg
      codesg segment
      mov ax,2000h
      mov ss,ax
      mov sp,0
      add sp,4
      pop ax
      pop bx
      push ax
      push bx
      pop ax
      pop bx
      mov ax,4c00h
      int 21h
      codesg ends
      end

    记录第一次出错:没有把t1.asm文件放在MASM611的BIN文件下。放入之后出现“Assembling:t1.asm”.
    在这里插入图片描述
    小结:汇编语言程序的汇编以及建立过程:
    编辑程序生成asm文件(t1.asm)——>汇编程序(masm t1.asm),将asm文件转换成ti.obj文件——>用LINK程序把obj文件转换成exe文件(link t1.obj)——>最后一步执行可以选择直接执行也可以选择使用debug命令单步执行

    1. 用Debug跟踪t1.exe的执行过程,写出每一步执行后相关寄存器中的内容
      在这里插入图片描述

    在这里插入图片描述

    1. PSP的前两个字节是CD 20,用Debug加载t1.exe,查看PSP的内容
      PSP的具体功能以及用法将会在后面的实验中逐渐提到,在这里可以先提前了解一下,这里的PSP是程序段前缀,这里的CD20是INT20h的机器码,可以先了解到这里,我会用一篇专门的博客来解释psp。在这里插入图片描述
      四.实验报告
      调试说明。包括上机调试的情况、上机调试步骤、调试所遇到的问题是如何解决的,并对调试过程中的问题进行分析,对执行结果进行分析。
    展开全文
  • gdb调试(c语言和汇编指令)

    千次阅读 2021-07-19 16:16:52
    背景:调试Intel ipp库 目录一、gcc的安装二、icc的安装三、编译器的使用3.1 基本用法3.1.1 查看命令文档3.1.2 基本的编译命令3.1.3 运行目标文件3.2 多文件编译3.2.1 源码3.2.2 编译命令3.2.3 运行命令3.3 编译...

    环境:
    ubuntu 18.04
    gdb
    背景:调试Intel ipp库

    一、gcc的安装

    直接apt安装(build-essential包里面包含了gcc,g++之类的工具)

    sudo apt install build-essential
    

    测试

    gcc -v
    

    二、icc的安装

    icc全称是Intel C++ Compiler,intel的文档中是使用的icc这个名称,但是实际的编译器可执行文件不叫icc,而是icx(不过好像在别的平台也有其它的编译器),在我这个文档里icc=icx

    参考ipp的安装的文档

    三、编译器的使用

    gcc和icx都是编译器,不过编译ippi代码时,使用gcc编译的话,有时会有问题(应该是c语言运行库不同),因此还是使用icx来编译吧(gcc作为一个通用的编译器来使用)

    3.1 基本用法

    3.1.1 查看命令文档

    文档内容很多,不需要全部了解

    icx --help
    

    3.1.2 基本的编译命令

    icx helloworld.c -o helloworld
    

    命令说明:helloworld.c为源文件,helloworld为目标文件

    3.1.3 运行目标文件

    ./helloworld
    

    3.2 多文件编译

    3.2.1 源码

    编写三个文件main.c,foo.h,foo.c
    main.c

    #include <stdio.h>
    
    #include "foo.h"
    
    int main()
    {
        int a = 1, b = 2, c = 3;
        int res = foo(a, b, c);
        printf("a+b+c=%d\n", foo(a, b, c));
    
        return 0;
    }
    

    foo.h

    #ifndef __FOO_H__
    #define __FOO_H__
    
    #include "foo.h"
    
    int foo(int a, int b, int c);
    
    #endif // __FOO_H__
    

    foo.c

    #include "foo.h"
    
    int foo(int a, int b, int c){
        return a+b+c;
    }
    

    3.2.2 编译命令

    gcc main.c foo.c -g -o main
    

    3.2.3 运行命令

    ./main
    

    3.3 编译双线性变换demo

    以intel提供的GetBilinearTransform.c为例

    3.3.1 编译命令

    icx GetBilinearTransform.c -g -static -o GetBilinearTransform -I$IPPROOT/include -L$IPPROOT/lib/intel64 -lippi -lipps -lippcore
    

    命令说明:

    • GetBilinearTransform.c为源文件
    • -g表示为调试添加符号信息
    • -static表示静态编译(静态编译的话,调试起来方便一些,不过不是必须的
    • -o GetBilinearTransform表示目标文件为GetBilinearTransform,
    • -I$IPPROOT/include表示添加头文件搜索路径
    • -L$IPPROOT/lib/intel64表示添加库搜索路径
    • -lippi,-lipps-lippcore表示链接libippi.so,libipps.so,libippcore.so这三个库文件

    3.3.2 运行命令

    ./GetBilinearTransform
    

    3.4 编译金字塔demo

    3.4.1 编译命令

    icx Pyramid.c -g -static -o Pyramid -IPPROOT/include -LPPROOT/lib/intel64 -lippi -lipps -lippcore -lippcv
    

    命令说明:

    • Pyramid.c为源文件
    • -g表示为调试添加符号信息
    • -static表示静态编译(静态编译的话,调试起来方便一些,不过不是必须的
    • -o Pyramid表示目标文件为Pyramid
    • -I$IPPROOT/include表示添加头文件搜索路径
    • -L$IPPROOT/lib/intel64表示添加库搜索路径
    • -lippi,-lipps,-lippcore-lippcv表示链接libippi.so,libipps.so,libippcore.so,libippcv.so,这四个库文件

    3.4.2 运行命令

    ./Pyramid
    

    三、gdb的安装

    两种方法,源码安装apt安装

    方法1 (推荐)apt安装gdb

    sudo apt install gdb 
    

    方法2 源码安装

    参考gdb 10.2的安装

    测试

    gdb -v
    

    四、gdb的使用

    4.1 gdb命令行调试c程序

    4.1.1 gdb启动命令

    直接gdb 目标文件即可,以前面编译的main为例

    gdb main
    

    4.1.2 gdb断点命令(b/break)

    断点命令介绍

    gdb中设置断点的命令为b[reak]break是完整命令,不过一般是使用简称b代替。
    gdb中有很多种断点(参考链接),这里只介绍常用的几个

    • 根据函数名设置断点。命令为b 函数名b *函数名, 需要注意的是,b *函数名b 函数名在c语言级别好像没区别,但是在汇编级别是有区别的。简单来说就是b *函数名要比b 函数名的断点更靠前,这个实际运行一下就知道了。
    • 根据行号设断点。b linenum 或者break filename:linenumfilename为文件名,为空表示当前文件,linenum为行号。
    • 根据指令地址设置断点。b *addr,其中addr为指令地址(如果动态链接的动态库还没有加载的话,可能会报错)。

    示例

    函数断点最常用,因此在这里演示函数断点。继续前面的操作,在gdb中输出命令 b foo
    如图:
    在这里插入图片描述

    其它关于断点的命令

    • info b, 简写为i b 查看断点信息,打印的信息中包括断点的编号,断点类型,是否一直生效,是否启用,断点地址,断点位置等。
    • disable b,简写为dis b num,将编号为num的断点暂时禁用
    • enable b,简写为ena b num,将编号为num的断点启用
    • cleardelete,删除所有断点
      除此之外,还有条件断点监控断点等等,此处略。

    4.1.3 gdb运行命令(r/run)

    运行命令为r[un],简称为r
    继续上面的操作,键入命令r,如下图
    在这里插入图片描述
    可以看到程序在foo函数处停下来了,且上面显示了foo函数的参数。

    4.1.4 gdb查看代码命令(l/list)

    如图
    在这里插入图片描述

    4.1.5 查看当前代码运行位置(bt/backtrace)

    查看当前代码位置,也即查看调用堆栈,可以使用命令backtrace,简称bt,如图,可以看到当前位置,栈1为main.c的第8行,栈0为foo.c的第4行
    在这里插入图片描述

    4.1.6 gdb打印变量命令(p/print)

    help p可以看到p的使用方法,这里也只说几种比较常见的用法。
    示例:
    p /t var, 以二进制打印var
    p /d var, 以十进制打印var
    p /x var, 以十六进制打印var
    p /f var, 以浮点数形式打印var
    在这里插入图片描述
    另外,p命令里面也可以直接进行运算,比如加减乘除
    p /d 0x10+0x20
    p /d a-0x20
    p /d 0x10*b
    p /d a/b

    4.1.7 gdb下一行代码命令(n/next)

    下一行命令为n[ext],简称为n
    单独的n,表示跳到下一行
    当然也可以一次跳很多行,n num,表示跳num行代码
    如图,我们从foo.c的第四行跳到了foo.c的第5行
    在这里插入图片描述

    4.1.8 gdb继续执行命令(c/continue)

    继续执行命令为c[ontinue],简称为c,继续执行直到遇到下一个断点。

    4.1.9 gdb进入函数命令(s/step)

    进入函数指令为s[tep],简写s
    n的区别就是,当当前代码为函数调用时,n不会进入函数内部,s会进入函数内部

    4.1.6 其它命令

    finish 退出函数体
    unitl 退出循环
    set $i=1 设置临时变量,也可以用来动态修改寄存器的值,比如可以修改x86的eflags寄存器来改变程序的运行流程(参考)

    4.2 使用gdb的tui调试c程序

    tui命令参考

    写在前面

    gdb的tui图形化有bug,有时屏幕会花掉,这个时候不用慌,只要刷新一下即可,快捷键是ctrl+L

    4.2.1 启动tui

    虽然一般使用gdb都是直接使用命令行的,不过gdb也提供了tui来实现简单的可视化,启动tui的方法有很多,这里只介绍我觉得比较方便的。

    • 方式1:在gdb里面输入命令tui enable
    • 方式2:在gdb里面输入命令layout src(这里的src表示源码显示)

    tui的初始界面如下图所示
    在这里插入图片描述
    图中的箭头指示的就是当前代码的位置,b+表示的是断点位置,当前是两个位置重合了。

    4.2.2 tui的退出

    退出tui,即返回命令行界面

    • 方式一:使用组合快捷键, ctrl+xa(操作就是先按ctrl+x,然后再按a
    • 方式二:输入命令tui disable

    4.2.3 tui的一些设置

    • focus cmd
      tui的一些默认设置我觉得很难受,比如进入tui之后,默认选中的是代码区域(比如前面图中,可以看到代码窗口(src window)周围有一圈蓝色,这表示代码区域被选中)。代码窗口被选中的情况下,键盘的上下左右键就变成了移动代码窗口,你输入命令的时候甚至不能往左边移动光标(虽然快捷键ctrl+b可以做到,但是也太反人类了),总之这样很不方便。解决办法就是输入focus cmd命令来选中命令窗口,这样就ok了,如下图
      在这里插入图片描述

    4.2 gdb命令行调试汇编程序

    依然以上面的main程序为例,但是我们现在对它进行汇编级调试,为了直观,我们启用tui。

    4.2.1 启动gdb

    方法和前面相同,此处设置了三个断点mainfoo*foo。(注意,foo的断点在*foo断点之后,具体原理应该和堆栈有关,略)

    ubuntu@WZY:~/test$ gdb main
    GNU gdb (GDB) 10.2
    Copyright (C) 2021 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    Type "show copying" and "show warranty" for details.
    This GDB was configured as "x86_64-pc-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <https://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
        <http://www.gnu.org/software/gdb/documentation/>.
    
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from main...
    (gdb) b main
    Breakpoint 1 at 0x652: file main.c, line 7.
    (gdb) b foo
    Breakpoint 2 at 0x6b5: file foo.c, line 4.
    (gdb) b *foo
    Breakpoint 3 at 0x6a8: file foo.c, line 3.
    (gdb) i b
    Num     Type           Disp Enb Address            What
    1       breakpoint     keep y   0x0000000000000652 in main at main.c:7
    2       breakpoint     keep y   0x00000000000006b5 in foo at foo.c:4
    3       breakpoint     keep y   0x00000000000006a8 in foo at foo.c:3
    

    4.2.2 启动tui的汇编窗口

    与前面不同,这里的tui启动命令改为layout asm,其中asm表示汇编,如下图所示,显示的就是汇编代码了
    在这里插入图片描述

    4.2.3 设置汇编风格为intel

    个人习惯intel的汇编风格,因为AT的汇编中mov的目标寄存器在右侧,实在不习惯,但是gdb的默认汇编风格为AT,因此要手动进行切换。切换命令为

    set disassembly-flavor intel
    

    4.2.4 汇编级别的跳转指令

    • 跳到下一条指令, nexti,简写ni
    • 进入函数调用,stepi,简称si
    • 其它的跳转指令,和c语言级别的一样,略

    4.2.5 tui显示寄存器的值

    tui除了之前提到的srcasm窗口外,还有一个reg窗口,这个窗口会显示寄存器的值。
    显示命令如下

    • tui reg general 显示通用寄存器
    • tui reg vector 显示向量寄存器
    • tui reg all 显示所有寄存器
    • 其它类型可以自行查看,方法是键入tui reg,然后按两下tab键会显示命令补全。

    tui reg general 如下图
    在这里插入图片描述

    4.2.6 打印寄存器的值

    p $reg 可以打印某个寄存器的值,其中p命令的参数和前面提到的一致。
    例如:

    (gdb) p $rsp  
    $1 = (void *) 0x7ffffffec698
    

    特别的,打印xmm寄存器时,默认输出内容很多。比如下面所示(我把xmm1寄存器的每个字节从低地址到高地址设置成了{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})

    (gdb) p $xmm1
    $2 = {v8_bfloat16 = {9.477e-38, 1.54e-36, 2.501e-35, 4.063e-34, 6.596e-33, 1.071e-31, 1.738e-30, 2.82e-29}, v4_float = {
        1.53998961e-36, 4.06321607e-34, 1.07111903e-31, 2.82126017e-29}, v2_double = {5.447603722011605e-270,
        2.500364306227096e-231}, v16_int8 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, v8_int16 = {513, 1027, 1541,
        2055, 2569, 3083, 3597, 4111}, v4_int32 = {67305985, 134678021, 202050057, 269422093}, v2_int64 = {578437695752307201,
        1157159078456920585}, uint128 = 21345817372864405881847059188222722561}
    

    这是因为xmm寄存器里面的值可以以不同形式来读取,如果你知道你的xmm0寄存器里面的值具体类型的话,可以直接输入对应类型,如下

    (gdb) p $xmm1.v16_int8 
    $3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
    (gdb) p $xmm1.v16_int8[1]
    $4 = 2
    (gdb) p $xmm1.v16_int8[10]
    $11 = 11
    (gdb) p $xmm1.v8_int16 
    $7 = {513, 1027, 1541, 2055, 2569, 3083, 3597, 4111}
    (gdb) p /x $xmm1.v8_int16
    $8 = {0x201, 0x403, 0x605, 0x807, 0xa09, 0xc0b, 0xe0d, 0x100f}
    (gdb) p /f $xmm1.v2_double
    $10 = {5.447603722011605e-270, 2.500364306227096e-231}
    

    另外,wsl好像不能成功识别ymm寄存器,因此无法看到ymm寄存器里面的值。我在我真实的linux上跑的时候,可以正常看到ymm寄存器
    如果想要看ymm寄存器的值的话,可以装个linux系统,虚拟机没试过,不过感觉应该也可以

    4.2.5 打印内存中的值

    使用x命令,help x可以看到x命令的使用方法

    (gdb) help x
    Examine memory: x/FMT ADDRESS.
    ADDRESS is an expression for the memory address to examine.
    FMT is a repeat count followed by a format letter and a size letter.
    Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),
      t(binary), f(float), a(address), i(instruction), c(char), s(string)
      and z(hex, zero padded on the left).
    Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).
    The specified number of objects of the specified size are printed
    according to the format.  If a negative number is specified, memory is
    examined backward from the address.
    
    Defaults for format and size letters are those previously used.
    Default count is 1.  Default address is following last thing printed
    with this command or "print".
    

    如文档所示,x的format可以指定解析方式size。其中size的类型有b(byte), h(halfword), w(word), g(giant, 8 bytes),在这里一个word为32位(值得一提的是,intel的汇编里面一个word为16位,double word为32位,quad word为64位,不要弄混,我建议是不要去记gdb里面的word宽度,知道w是32位,g是64位就差不多了
    直接举例子吧,
    x /xw 0x123456 以16进制打印,地址为0x123456,数据宽度为32位(word)
    x /xg 0x123456 以16进制打印,地址为0x123456,数据宽度为64位(8 bytes)
    x /fg $rsp+0x18 以浮点数打印,地址为$rsp+0x18,数据宽度为64位(8 bytes),64位的浮点数也就等价于c语言中的double
    x /fw $rsp+0x18 以浮点数打印,地址为$rsp+0x18,数据宽度为32位(4 bytes),32位的浮点数也就等价于c语言中的float
    x /4xb $rsp-0x18 以16进制打印,地址为$rsp-0x18,数据宽度为8位(byte),连着打印4个
    x /8dh $rsp-0x18 以10进制打印,地址为$rsp-0x18,数据宽度为16位(halfword),连着打印8个
    另外,

    • 如果你手误写重复了,gdb好像默认是第一个选项
      比如x /xdf $rspx /4x $rsp一样,x /xbwg $rspx /xb $rsp一样
    • 如果你没有设置格式,默认和上次的格式一致

    4.2.6 反汇编某个函数

    使用gdb的disassemble可以得到某个函数的反汇编代码

    (gdb) disassemble main
    Dump of assembler code for function main:
       0x000000000000064a <+0>:     push   %rbp
       0x000000000000064b <+1>:     mov    %rsp,%rbp
       0x000000000000064e <+4>:     sub    $0x10,%rsp
       0x0000000000000652 <+8>:     movl   $0x1,-0x10(%rbp)
       0x0000000000000659 <+15>:    movl   $0x2,-0xc(%rbp)
       0x0000000000000660 <+22>:    movl   $0x3,-0x8(%rbp)
       0x0000000000000667 <+29>:    mov    -0x8(%rbp),%edx
       0x000000000000066a <+32>:    mov    -0xc(%rbp),%ecx
       0x000000000000066d <+35>:    mov    -0x10(%rbp),%eax
       0x0000000000000670 <+38>:    mov    %ecx,%esi
       0x0000000000000672 <+40>:    mov    %eax,%edi
       0x0000000000000674 <+42>:    call   0x6a8 <foo>
       0x0000000000000679 <+47>:    mov    %eax,-0x4(%rbp)
       0x000000000000067c <+50>:    mov    -0x8(%rbp),%edx
       0x000000000000067f <+53>:    mov    -0xc(%rbp),%ecx
       0x0000000000000682 <+56>:    mov    -0x10(%rbp),%eax
       0x0000000000000685 <+59>:    mov    %ecx,%esi
       0x0000000000000687 <+61>:    mov    %eax,%edi
       0x0000000000000689 <+63>:    call   0x6a8 <foo>
       0x000000000000068e <+68>:    mov    %eax,%esi
       0x0000000000000690 <+70>:    lea    0xbd(%rip),%rdi        # 0x754
       0x0000000000000697 <+77>:    mov    $0x0,%eax
       0x000000000000069c <+82>:    call   0x520 <printf@plt>
       0x00000000000006a1 <+87>:    mov    $0x0,%eax
       0x00000000000006a6 <+92>:    leave  
       0x00000000000006a7 <+93>:    ret    
    End of assembler dump.
    

    多啰嗦一句
    直接从终端复制反汇编代码的话,格式比较乱,我建议在gdb中使用管道命令把反汇编代码直接重定向到本地文件中,具体命令为pipe disassemble main | tee main.asm,其中main.asm为目标文件名

    4.2.7 在根据指令地址设置断点

    这个功能听着挺实用的,因为它能最准确地跳到你想调试的地方,设置的方法很简单,前面也提到过,就是,其中addr为指令地址(b *func和这个原理应该是一样的)。
    但是用起来会有蛮多限制条件,一不小心就容易报错。

    1、动态链接库的符号加载,动态链接库在没有加载之前是没有实际地址的,因此设置断点时会出现下面这个错误

    (gdb) b *l9_ownpi_WarpBilinearBack + 4
    No symbol "l9_ownpi_WarpBilinearBack" in current context.
    

    当然你可以在main函数处设置断点,然后运行到断点处,此时由于动态库的符号表已经加载进来所以,可以成功设断点。但是当你r之后,会发现断点又失效了,解决办法是先disable断点,然后r,等进入main函数后再enable断点,然后c,就又可以成功了(不知道有没有其它更好的办法),整个流程如下

    ubuntu@WZY:~/ipp/gdb$ gdb-oneapi gdb_WarpBilinearBack
    ......
    For help, type "help".
    Type "apropos word" to search for commands related to "word"...
    Reading symbols from gdb_WarpBilinearBack...
    (gdb) b *l9_ownpi_WarpBilinearBack + 4
    No symbol "l9_ownpi_WarpBilinearBack" in current context.
    (gdb) b main
    Breakpoint 1 at 0x400f9b: file gdb_WarpBilinearBack.c, line 84.
    (gdb) c
    The program is not being run.
    (gdb) r
    Starting program: /home/ubuntu/ipp/gdb/gdb_WarpBilinearBack 
    
    Breakpoint 1, main (argv=1, args=0x7ffffffec748) at gdb_WarpBilinearBack.c:84
    84          IppStatus status = ippStsNoErr;
    (gdb) b *l9_ownpi_WarpBilinearBack + 4
    Breakpoint 2 at 0x7ffffc555044
    (gdb) c
    Continuing.
    
    Breakpoint 2, 0x00007ffffc555044 in l9_ownpi_WarpBilinearBack () from /opt/intel/oneapi/ipp/2021.1.1/lib/intel64/libippil9.so.10.0
    (gdb) c
    Continuing.
    
    Exit status 0 (ippStsNoErr: No errors)
    [Inferior 1 (process 18633) exited normally]
    (gdb) r
    Starting program: /home/ubuntu/ipp/gdb/gdb_WarpBilinearBack 
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    
    Breakpoint 1, main (argv=1, args=0x7ffffffec748) at gdb_WarpBilinearBack.c:84
    84          IppStatus status = ippStsNoErr;
    (gdb) c
    Continuing.
    
    Exit status 0 (ippStsNoErr: No errors)
    [Inferior 1 (process 18637) exited normally]
    (gdb) info b
    Num     Type           Disp Enb Address            What
    1       breakpoint     keep y   0x0000000000400f9b in main at gdb_WarpBilinearBack.c:84
            breakpoint already hit 1 time
    2       breakpoint     keep n   0x00007ffffc555044 <l9_ownpi_WarpBilinearBack+4>
    (gdb) dis 2
    (gdb) r
    Starting program: /home/ubuntu/ipp/gdb/gdb_WarpBilinearBack 
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    Error in re-setting breakpoint 2: No symbol "l9_ownpi_WarpBilinearBack" in current context.
    
    Breakpoint 1, main (argv=1, args=0x7ffffffec748) at gdb_WarpBilinearBack.c:84
    84          IppStatus status = ippStsNoErr;
    (gdb) en 2
    (gdb) c
    Continuing.
    
    Breakpoint 2, 0x00007ffffc555044 in l9_ownpi_WarpBilinearBack () from /opt/intel/oneapi/ipp/2021.1.1/lib/intel64/libippil9.so.10.0
    (gdb) 
    

    2、静态编译出来的程序使用这种断点目前没问题,但是我也不清楚以后会不会有别的问题。成功示例如下(使用静态编译的程序)

    (gdb) b *l9_ownpi_WarpBilinearBack + 4
    Breakpoint 1 at 0x4b58a4
    (gdb) r
    Starting program: /home/ubuntu/ipp/gdb/gdb_WarpBilinearBackStatic 
    
    Breakpoint 1, 0x00000000004b58a4 in l9_ownpi_WarpBilinearBack ()
    (gdb) 
    
    展开全文
  • 使用GDB(三):调试程序汇编方法

    千次阅读 2021-10-16 17:50:40
    但是有同一般解释器不一样的地方,LuaJit的作者搞了个叫DynASM的工具,通过DynASM预处理可以把汇编指令变成可执行的二进制码,所以解释模式解释执行byte code的逻辑是用汇编写的,如下: |//符合DynASM语法的

    使用GDB调试程序的时候经常会遇到这样的情况,键入s或者c命令,进入某个函数,然后键入l命令想看这个函数的代码,发现无法查看,但是在这个函数的内部,又发生了错误,此时我们就想到了利用反汇编disassemble命令查看汇编代码:

    (gdb) c
    Breakpoint 2, 0x000000012003b020 in lj_BC_JLOOP ()
    (gdb) l
    570	}
    571	
    572	int main(int argc, char **argv)
    573	{
    574	  int status;
    575	  lua_State *L = lua_open();
    576	  if (L == NULL) {
    577	    l_message(argv[0], "cannot create state: not enough memory");
    578	    return EXIT_FAILURE;
    579	  }
    (gdb) bt
    #0  0x000000012003b020 in lj_BC_JLOOP ()
    Backtrace stopped: Cannot access memory at address 0x8a
    (gdb) disassemble 
    Dump of assembler code for function lj_BC_JLOOP:
       0x000000012003b00c <+0>:	addu16i.d	$r20,$r0,-2856(0xf4d8)
       0x000000012003b010 <+4>:	srai.d	$r20,$r20,0x10
       0x000000012003b014 <+8>:	ldx.d	$r13,$r26,$r20
       0x000000012003b018 <+12>:	addu16i.d	$r20,$r0,0
       0x000000012003b01c <+16>:	srai.d	$r20,$r20,0x10
    => 0x000000012003b020 <+20>:	or	$r19,$r0,$r20
       0x000000012003b024 <+24>:	add.d	$r13,$r13,$r10
       0x000000012003b028 <+28>:	addu16i.d	$r20,$r0,-3792(0xf130)
       0x000000012003b02c <+32>:	srai.d	$r20,$r20,0x10
       0x000000012003b030 <+36>:	stx.d	$r19,$r26,$r20
       0x000000012003b034 <+40>:	ld.d	$r14,$r13,0
       0x000000012003b038 <+44>:	addu16i.d	$r20,$r0,-3600(0xf1f0)
       0x000000012003b03c <+48>:	srai.d	$r20,$r20,0x10
       0x000000012003b040 <+52>:	stx.d	$r23,$r26,$r20
       0x000000012003b044 <+56>:	ld.d	$r14,$r14,88(0x58)
       0x000000012003b048 <+60>:	addu16i.d	$r20,$r0,-3752(0xf158)
       0x000000012003b04c <+64>:	srai.d	$r20,$r20,0x10
       0x000000012003b050 <+68>:	stx.d	$r27,$r26,$r20
       0x000000012003b054 <+72>:	addu16i.d	$r20,$r0,28792(0x7078)
       0x000000012003b058 <+76>:	srai.d	$r20,$r20,0x10
       0x000000012003b05c <+80>:	add.d	$r22,$r26,$r20
       0x000000012003b060 <+84>:	jirl	$r0,$r14,0
    End of assembler dump.
    (gdb) 
    

    但是有些特殊情况下使用disassemble命令无法反汇编,这时候还可以取出程序PC所指代码段的那一块内存中的值,再对其反汇编生成汇编代码,由下面信息可知,当前PC值为0x000000012003b020

    (gdb) c
    Breakpoint 2, 0x000000012003b020 in lj_BC_JLOOP ()
    (gdb) bt
    #0  0x000000012003b020 in lj_BC_JLOOP ()
    

    查看内存0x000000012003b020周围存放的内容,x /20xw 0x000000012003b020命令是从0x000000012003b020处开始向后查找20个单位内存中的值,以十六进制显示,每个单位的长度是一个字(4字节)。这里之所以选择4个字节,是因为我现在使用的目标指令是longarch指令集,指令长度均是32位。

    (gdb) x /20xw 0x000000012003b020
    0x12003b020 <lj_BC_JLOOP+20>:	0x00155013	0x0010a9ad	0x13c4c014	0x00494294
    0x12003b030 <lj_BC_JLOOP+36>:	0x381c5353	0x28c001ae	0x13c7c014	0x00494294
    0x12003b040 <lj_BC_JLOOP+52>:	0x381c5357	0x28c161ce	0x13c56014	0x00494294
    0x12003b050 <lj_BC_JLOOP+68>:	0x381c535b	0x11c1e014	0x00494294	0x0010d356
    0x12003b060 <lj_BC_JLOOP+84>:	0x4c0001c0	0x0044854c	0x029ffc13	0x00409673
    

    将上面查到的值存放到一个.s汇编文件中,修改格式,去掉没有用的内容,^@是换行符\n

    .long 0x00155013^@.long 0x0010a9ad^@.long 0x13c4c014^@.long 0x00494294
    .long 0x381c5353^@.long 0x28c001ae^@.long 0x13c7c014^@.long 0x00494294
    .long 0x381c5357^@.long 0x28c161ce^@.long 0x13c56014^@.long 0x00494294
    .long 0x381c535b^@.long 0x11c1e014^@.long 0x00494294^@.long 0x0010d356                                                                                                                        
    .long 0x4c0001c0^@.long 0x0044854c^@.long 0x029ffc13^@.long 0x00409673
    

    然后再对汇编文件进行汇编,汇编完后生成一个.o文件,最后再对.o文件反汇编:

    [loongson@localhost workfile]$ vim ass.s 
    [loongson@localhost workfile]$ gcc -c ass.s -o ass.o
    [loongson@localhost workfile]$ objdump -d ass.o 
    
    ass.o:     文件格式 elf64-loongarch
    
    
    Disassembly of section .text:
    
    0000000000000000 <.text>:
       0:	00155013 	or	$r19,$r0,$r20
       4:	0010a9ad 	add.d	$r13,$r13,$r10
       8:	13c4c014 	addu16i.d	$r20,$r0,-3792(0xf130)
       c:	00494294 	srai.d	$r20,$r20,0x10
      10:	381c5353 	stx.d	$r19,$r26,$r20
      14:	28c001ae 	ld.d	$r14,$r13,0
      18:	13c7c014 	addu16i.d	$r20,$r0,-3600(0xf1f0)
      1c:	00494294 	srai.d	$r20,$r20,0x10
      20:	381c5357 	stx.d	$r23,$r26,$r20
      24:	28c161ce 	ld.d	$r14,$r14,88(0x58)
      28:	13c56014 	addu16i.d	$r20,$r0,-3752(0xf158)
      2c:	00494294 	srai.d	$r20,$r20,0x10
      30:	381c535b 	stx.d	$r27,$r26,$r20
      34:	11c1e014 	addu16i.d	$r20,$r0,28792(0x7078)
      38:	00494294 	srai.d	$r20,$r20,0x10
      3c:	0010d356 	add.d	$r22,$r26,$r20
      40:	4c0001c0 	jirl	$r0,$r14,0
      44:	0044854c 	srli.w	$r12,$r10,0x1
      48:	029ffc13 	addi.w	$r19,$r0,2047(0x7ff)
      4c:	00409673 	slli.w	$r19,$r19,0x5
    

    将第二次反汇编生成的汇编代码和第一次生成的汇编代码比较,两次内容完全一样。比较的时候注意位置,是从第一次的=> 0x000000012003b020 <+20>:处开始比较的。如果想知道0x000000012003b020地址之前的代码段,只需要将其值以4的倍数减少(newAddr = 0x000000012003b020 - 4 * n),从newAddr开始查找指定格式、范围和大小的内存中的值,反汇编即可。

    展开全文
  • Linux环境下做C语言项目,项目工程庞大复杂,出现了不少问题,其中遇到最多、花费时间最长的问题就是著名的“段错误”(Segmentation Fault)。借此机会系统学习了一下。 1. 段错误是什么 一句话来说,段错误是指...
  • vs 2019编写汇编并运行调试

    万次阅读 多人点赞 2019-09-08 15:00:07
    我是上学期学的汇编,因为有vs又不想用课上教的麻烦的dosbox以及masm32,但是一直没找到高亮插件和能调试的(难运行不了而找不到答案上,出现的错误在最后放出,还请先达们不吝指点)汇编代码所以放弃了。...
  • linux下ARM汇编程序调试

    千次阅读 2016-02-01 00:00:00
    最近学习ARM的汇编,但是ARM不像x86,可以很方便的调试。...Google了很久,又结合自己的实践,终于成功的调试了ARM的汇编此向对ARM嵌入式感兴趣的同学分享一下。 首先说明需要的工具 1. QEMU 
  • 汇编语言的心得体会

    2021-07-30 03:07:04
    汇编语言的心得体会》由会员分享,可在线阅读,更多相关《汇编语言的心得体会(2页珍藏版)》请人人文库网上搜索。1、汇编语言的心得体会一、实验目的1、学习使用汇编语言、连接程序汇编语言源程序进行汇编、...
  • C程序中调用汇编函数

    千次阅读 2017-05-18 09:26:47
    赵炯的《Linux内核完全剖析》有一个C程序中调用汇编函数的介绍 执行as -o callee.o callee.s的时候遇到错误 “callee.s:7: Error: invalid instruction suffix for `push'”, 参考文章 :...
  • keil程序在外部RAM中调试的问题总结

    千次阅读 2018-07-14 22:48:41
    但是有些时候内部RAM并不够用,这就需要将程序装入外部RAM中调试,而这个过程可能会出现各种各样的问题,这里我将会把我遇到过的一些问题和需要注意的地方总结一下,希望能够对大家有所帮助。有错误的地方也...
  • 掌握debug能力可以快速解决编程中遇到的问题,但是很多初学者并不会,本文主要简单介绍如何使用VC6++进行程序调试。 一、首先介绍下使用debug前可能存在的问题: 1、找不到debug窗口 解决方法: ...
  • 汇编语言实习心得

    千次阅读 2021-07-30 03:05:54
    汇编语言实习心得发布时间:2020-01-02通过汇编语言实习,学生应该通过大量的上机实验熟悉8086 CPU的指令功能、用途和使用技巧,进而通过循序渐进的程序设计练习,验证各类指令的功能和提高程序设计的能力。...
  • 入门masm32编写简单汇编程序并做具体分析

    万次阅读 多人点赞 2017-10-19 00:56:27
    用masm32编写一个很简单的汇编程序来入门一下masm32,打算使用斐波拉切数列这个简单的小程序来作为例子讲述。
  • 如果没有一个连接到当前程序调试器,则程序将停止这行语句处无法继续执行。上面的这种方式称为高级语言和汇编语言混编。当我用得正爽的时候,迎头碰到了64位平台这员猛将。它大手一张,挑出一张禁令通知单:64...
  • 但是实际应用,GDB 更常用来调试C和C++程序。虽然说Linux系统下我们可以借助诸多集成开发工具来完成程序的编写和调试,但实际上,调试C/C++程序一定是直接或者间接使用GDB完成的。所以说GDB调试几乎可以说是...
  • 熟悉分支结构设计与调试 题目要求:设有字无符号数X、Y,试编制求Z=|X-Y| 流程图: 二.实验步骤 1.将MASM文件夹复制到D:盘根目录下 2.将编好的代码复制到MASM文件夹,扩展名改为’.asm’ 3.搭建DOSBox-汇编环境 4....
  • 8086 汇编程序报错信息解释

    千次阅读 2020-06-22 12:46:52
    8086 汇编语言 本文介绍了 汇编过程中报的错误信息说明
  • 使用gdb调试程序完全教程

    万次阅读 多人点赞 2016-06-14 14:21:48
    程序调试过程主要有:单步执行,跳入函数,跳出函数,设置断点,...分析现象 -> 假设错误原因 -> 产生新的现象去验证假设调试器(如GDB)的目的是允许你在程序运行时进入到某个程序内部去看看该程序在做什么,或者
  • c语言调试技巧总结

    2021-05-20 01:06:46
    c语言调试技巧总结2007-12-31 20:38:19|分类: 编程资料 |标签:|字号大中小经过这么多程序的编辑与调试,需要总结一些经验,以免以后的调试中当初无知的起点出发开始摸索!整个程序编辑完毕并通过编译后,对...
  • VS2019调试查看变量_调试c++程序

    千次阅读 2020-11-05 23:50:02
    另一个办法就是一般说的调试( debug ),在程序中设置断点( breakpoint ),程序运行到断点时暂停,且可以查看各个变量的具体值。1.介绍程序运行过程为:预处理 -> 编译和优化 -> 生成目标文...
  • KEIL5Debug调试

    万次阅读 多人点赞 2021-05-07 11:49:41
    文章目录前言一、进入调试二、介绍调试工具栏二、搜索寻找三、...一步一步的运行调试程序检查错误,或者直接运行到某处,二话不多说,开整! 一、进入调试 二、介绍调试工具栏 1 . 复位按钮:(类似于用复位按键..
  • gdb调试程序实例

    千次阅读 2017-06-26 15:53:47
    GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具。或许,各位比较喜欢那种图形界面方式的,像VC、BCB等IDE的调试,但如果你是UNIX平台下做软件,你会发现GDB这个调试工具有比VC、BCB的图形化调试器更强大的...
  • 好久没有遇到这么有趣的 Bug 了,来抓一个调试指针出现偏移错误❌的。 C++ 实现的派生类和类重写的两个虚函数 A、B 后,代码实写调用 A 函数,断点 Debug 调试却命中 B 函数。 win10 21H2 Visual Studio 2019 ...
  • 汇编语言编写的基本程序可以正常工作和调试,编译后的C或C ++代码更有可能遇到错误处理的指令。 尽管也接受S19,但是建议以ELF格式加载可执行文件。 资源目录提供了一个示例程序。 这会将滚动文本输出到LCD。 ...
  • 汇编程序:MASM.EXE,用于汇编源程序,得到目标程序。 连接程序:LINK.EXE,用于连接目标程序,得到可执行程序。 调试程序:DEBUG.EXE,用于调试可执行程序。 二、上机过程 汇编语言程序上机操作包括:编辑、汇编、...
  • 今天使用gdb调试程序函数A处打断点, 执行到断点时, 单步调试进入这个函数, 但是与预期的结果不同, 进入函数B了, 没有进入到函数A, 发截图给组内的大佬, 让仔细看 gdb 调试时输出的信息, 查找后发现 ...
  • linux反汇编简单示例

    千次阅读 2021-07-29 09:59:06
    复杂比较难的程序中比如内核调试,会用到反汇编调试,当程序遇到一些未知的变量错误等,可以直接反汇编来查看汇编代码,一切一目了然。这里介绍一个反汇编的使用方法 需要用到的工具 objdump objdump安装 ubuntu...
  • ARM汇编调试

    2016-02-01 00:00:00
    最近学习ARM的汇编,但是ARM不像x86,可以很方便的调试。...Google了很久,又结合自己的实践,终于成功的调试了ARM的汇编此向对ARM嵌入式感兴趣的同学分享一下。 首先说明需要的工具 1. QEMU 
  • OllyDbg动态调试与逆向破解TraceMe.exe

    千次阅读 2021-10-05 22:26:04
    OllyDbg 是一个新的动态追踪工具,是将 IDA 与 SoftICE 结合起来的产物,Ring3 级调试器,非常容易上手,另外由于 OllyDbg 是一个通用的 32 位汇编分析调试器且操作界面非常直观简单,己代替 SoftICE 成为当今最为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,146
精华内容 8,458
热门标签
关键字:

在汇编程序调试中遇到的错误