linux平台学x86汇编(五):使用gdb调试汇编程序

【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】

正如C语言一样,编写所有语言程序一样会出现一些一些错误,发生错误时,我们可以使用调试器一步一步运行程序以监视数据是如何被处理的。本节使用GNU调试器检查上一节hello程序,监视处理过程中寄存器和内存的值的变化。要调试汇编语言程序,在编译时,需要使用-gstabs参数重新汇编源代码,使用了该参数编译出来的可执行文件要比之前稍大一些,因为添加了附加信息。上一节程序不使用-gstabs参数汇编生成文件如下:

$ ls -lh hello

-rwxrwxr-x. 1 allen allen 628 4月  11 15:28 hello

使用-gstabs之后,编译后生成文件如下:

$ ls -lh hello

-rwxrwxr-x. 1 allen allen 888 4月  11 15:29 hello

由于gnu调试时忽略开始处断点, 需要在开始标签处执行一个空指令nop。

当程序包含了必要的调试信息时,我们就可以在gdb中运行它:

$gdb hello

GNU gdb (GDB) Red Hat Enterprise Linux (7.2-60.el6)

Copyright (C) 2010 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 "i686-redhat-linux-gnu".

For bug reporting instructions, please see:

<http://www.gnu.org/software/gdb/bugs/>...

Reading symbols from /home/allen/as/1_hello/hello...done.

(gdb)

在gdb中,使用命令break(b)指定断点:

(gdb) break *_start

Note: breakpoint 1 also set at pc 0x8048074.

Breakpoint 2 at 0x8048074: file hello.s, line 12.

(gdb)

使用命令run(r)启动程序:

(gdb) run

Starting program: /home/allen/as/1_hello/hello

Breakpoint 1, _start () at hello.s:12

12    movl $len, %edx

(gdb)

可以看到程序启动了,停留在我们之前设置的断点处,使用next(n)和step(s)命令让程序单步执行:

(gdb) step

13    movl $msg, %ecx

(gdb) next

14    movl $1, %ebx

(gdb) s

15    movl $4, %eax

(gdb) n

16    int $0x80

(gdb)

在单步调试运行时可以查看检查数据元素值。最常被检查的元素是寄存器和内存位置,使用info register命令可以显示所有寄存器的值,使用print命令可以显示指定寄存器或变量的值,使用x命令显示指定内存位置的内容。

(gdb) info registers

eax            0x4 4

ecx            0x8049098 134516888

edx            0xd 13

ebx            0x1 1

esp            0xbffff3d0 0xbffff3d0

ebp            0x0 0x0

esi            0x0 0

edi            0x0 0

eip            0x8048088 0x8048088 <_start+20>

eflags         0x212 [ AF IF ]

cs             0x73 115

ss             0x7b 123

ds             0x7b 123

es             0x7b 123

fs             0x0 0

gs             0x0 0

(gdb)

使用命令print 加上指定寄存器也可以显示寄存器的值:

(gdb) print $eax

$1 = 4

(gdb) print $ebx

$4 = 1

(gdb) print $ecx

$5 = 134516888

(gdb) print $edx

$6 = 13

(gdb)

print命令加上修饰符可以改变pritn命令输出格式:

print/d 显示十进制的值

print/t显示二进制的值

print/x显示十六进制的值

(gdb) print/x $edx

$9 = 0xd

x命令也可以使用修饰符修改输出,其格式为:

x/nyz

n为要显示的字段数;

y是输出格式,可以是c(字符)、d(十进制)、x(十六进制);

z是要显示的字段的长度,可以是b(字节)、h(16位字)、w(32位字)。

(gdb) x/13cb &msg

0x8049098 <msg>: 104 ‘h‘ 101 ‘e‘ 108 ‘l‘ 108 ‘l‘ 111 ‘o‘ 32 ‘ ‘ 119 ‘w‘ 111 ‘o‘

0x80490a0 <msg+8>: 114 ‘r‘ 108 ‘l‘ 100 ‘d‘ 33 ‘!‘ 10 ‘\n‘

(gdb)

其中msg前的&表明其是一个内存位置。

命令cont使程序按正常的方式继续运行,没如果后面没有断点,则直接运行到最后。

(gdb) cont

Continuing.

Program exited normally.

(gdb)

最后可以使用quit命令退出gdb调试。

(gdb) quit

$

时间: 2024-10-14 10:36:14

linux平台学x86汇编(五):使用gdb调试汇编程序的相关文章

linux平台学x86汇编(十五):使用命令行参数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在高级语言中,程序在命令行上启动时常常带一个或多个参数,在汇编语言中也可以实现这一特性.在实现这一特性之前,我们先了解一下linux如何从命令行执行程序. 每一个应用程序开始执行时,系统都会为该程序分配一块内存区域,并且每个程序都分配相同的虚拟内存地址.虚拟内存地址由操作系统映射到物理内存地址.在Linux中,程序的虚拟内存地址是从0x80480000开始,到地址0xbfff

linux平台学x86汇编(六):数据的传送

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 前面讲了定义数据元素,既然定义了数据元素,那么就需要知道如何处理这些数据元素.数据元素位于内存中,并且处理器很多指令要使用寄存器,所以处理数据元素的第一个步骤就是在内存和寄存器之间传送它们.数据传送指令为mov,其为汇编语言中最常用的指令之一. mov指令的基本格式如下: movx source, dest 其中source和dest的值可以是内存地址.存储在内存中的数值.指

linux平台学x86汇编(三):相关开发工具

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 类似于其它高级语言,编写汇编语言,必须有一个开发环境,那么也就需要适当的工具了.搭建汇编语言至少应该有下面这些工具:汇编器.链接器.调试器.下下面看看在汇编语言开发环境中如何使用它们. 汇编器 汇编器用于把汇编语言源代码转换为处理器指令码.选择的汇编器必须能够生成所在系统的处理器系列指令码.汇编语言源代码程序有3个部分:操作码助记符.数据段.命令.但是每种汇编器对于每个部分使

linux平台学x86汇编(八):条件跳转

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 在此之前我们使用的汇编代码示例都是从第一条指令开始,直到最后最后一条指令程序退出.但实际上和高级语言类似,汇编代码也提供指令来改变程序处理数据方式. 正常情况下,程序要执行要执行的下一条指令是在指令指针寄存器中,指令指针确定程序中哪条指令是应该执行的下一条指令. 当指令指针在程序指令中移动时,EIP寄存器会递增.指令长度可能是多个字节,所以指向下一条指令不仅仅是每次是指令指针

linux平台学x86汇编(十九):C语言中调用汇编函数

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 除了内联汇编以外,还有一种途径可以把汇编代码整合到C/C++语言中,C/C++语言可以直接调用汇编函数,把输入值传递给函数,然后从函数获得输出值. 如果希望汇编语言函数和C/C++程序一起工作,就必须显示地遵守C样式的函数格式,也就是说所有输入变量都必须从堆栈读取,并且大多数输入值都返回到EAX嫁寄存器中.在汇编函数代码中,C样式函数对于可以修改哪些寄存器和函数必须保留哪些寄

linux平台学x86汇编(二十):汇编库的使用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 汇编语言和C一样,可以通过使用库来简化阻止大量函数的目标文件的问题.GNU C编译器可以不在命令行中独立地包含每个独立地函数目标文件,它允许吧所有目标文件组合在单一存档文件中.在编译C程序时,要做的工作就是包含单一的目标库文件,在编译时,编译器可以从库文件中挑出所需的正确目标文件.在库文件中,经常按照应用程序类型或者函数类型把函数分组在一起,单一应用程序项目可以使用多个库文件

linux平台学x86汇编(四):从“hello world!”开始

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 汇编语言程序由定义好的段构成,每个段有各自的目的.三个最常用的的段如下:数据段.bss段.文本段.文本段是可执行程序内声明指令码的地方,所有汇编程序都必须有文本段,数据段和bss段是可选的,但是在程序中经常使用.数据段声明带有初始值的变量,bss段声明使用0值初始化的数据元素,这些元素常用作汇编程序的缓冲区.下图为汇编语言程序的布局. GNU汇编器使用.section命令语句

linux平台学x86汇编(十八):内联汇编

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 使用汇编语言笔编程最常见的方式是在高级语言(C和C++)程序内编写汇编函数,这种吧汇编语言直接写到C和C++语言程序内的技术称为内联汇编. GNU的C编译器使用asm关键字指出使用汇编语言编写的源代码段落.asm段的基本格式如下: asm("as code"): 括号中的汇编指令必须在括号,指令超过一条的话必须使用新的行分隔汇编语言代码每一行,因为编译器逐字地取得a

linux平台学x86汇编(十四):函数的使用

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途] 和高级语言一样,汇编语言在多个项目之间可能会编写相同的过程和处理,如果使用函数的话就可以不必每次需要时都重复编写实用程序代码,从而在需要它的时候调用它. 函数包含完成特定功能所需的代码,数据从主程序传递给函数,然后结果返回给主程序.调用函数时,程序执行路径被改变,切换到函数代码的第一条指令.处理器从这个位置开始执行指令,直到函数表明它可以把控制返回到主程序中的原始位置. 在汇