实例
- demo.s
.section .data
output:
.ascii "The processor Vender ID is 'xxxxxxxxxxxx'\n"
.section .text
.globl _start
_start:
nop
// 获取 CPU ID
movl $0, %eax
cpuid
// 将 CPU ID 填充到 output 的占位符部分
movl $output, %edi
movl %ebx, 28(%edi)
movl %edx, 32(%edi)
movl %ecx, 36(%edi)
// 系统调用, 显示 CPUID
movl $4, %eax
movl $1, %ebx
movl $output, %ecx
movl $42, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
// 系统调用, 返回程序执行结果
movl $1, %eax
movl $0, %ebx
int $0x80
ret
编译链接
- 汇编器编译
as demo.s -32 -gstabs ld ./a.out demo -m elf_i386
- gcc 编译
gcc demo.s -o demo -m32 -g
使用 gdb 调试需要在as编译时加入参数 -gstabs
或者 gcc 加入 -g
.
调试
gdb ./demo
在 gdb 中执行 run 命令运行程序:
(gdb) run
Starting program: /home/shino/code/ass/a.out
The processor Vender ID is 'GenuineIntel'
[Inferior 1 (process 3031) exited normally]
(gdb)
可以看到程序正常执行并返回, gdb 调试常用命令如下
-
设置断点: break
格式为 break * label+offset, 比如在程序最开始设置断点:(gdb) break * _start Breakpoint 1 at 0x8049000: file demo.s, line 18. (gdb) break * _start + 5 Breakpoint 2 at 0x8049005: file demo.s, line 19. (gdb) run Starting program: /home/shino/code/ass/demo Breakpoint 1, _start () at demo.s:18 18 movl $0, %eax (gdb)
上述设置了两个断点, 一个是在起始地址
_start
, 另一个是相对_start
地址偏移了5个字节的地址, 这个地址刚好是cpuid
代码地址, 然后运行程序, 这时程序停在了断点 1 处. -
继续执行: cont
(gdb) cont Continuing. Breakpoint 2, _start () at demo.s:19 19 cpuid (gdb)
使用 cont 指令让代码继续运行, 代码往下执行遇到第二个断点停了下来.
-
单步运行: next 或 step
(gdb) next 22 movl $output, %edi (gdb)
使用
next
单步运行, 程序执当前行汇编指令, 并停在下一行. -
显示所有寄存器的值: info registers
(gdb) s 23 movl %ebx, 28(%edi) (gdb) info registers eax 0x1b 27 ecx 0x6c65746e 1818588270 edx 0x49656e69 1231384169 ebx 0x756e6547 1970169159 esp 0xffffcef0 0xffffcef0 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8049007 0x8049007 <_start+7> eflags 0x202 [ IF ] cs 0x23 35 ss 0x2b 43 ds 0x2b 43 es 0x2b 43 fs 0x0 0 gs 0x0 0 k0 0x0 0 k1 0x0 0 k2 0x0 0 k3 0x0 0 k4 0x0 0 k5 0x0 0 k6 0x0 0 k7 0x0 0 (gdb)
s 命令可用于报告当前位置
-
显示特定寄存器或者来自程序的变量的值: print
- print/d 以十进制显示
- print/t 以二进制显示
- print/x 以十六进制显示
(gdb) print/x $ebx $1 = 0x756e6547 (gdb)
显示了 EBX 寄存器的值
-
显示特定内存位置的内容: x
x 命令的格式是 x/nyz, 和 print 类型, x 可以使用 / 后面的修饰符改变输出结果, 各个修饰符的含义如下- n : 直接用数字表示要显示的字段数.
- y : 设置输出格式
- c 输出字符
- d 输出十进制
- x 输出十六进制
- z 设置每个字段的长度
- b 用于字节
- h 用于 16 位字
- w 用于 32 位字
(gdb) x/42cb &output 0x804a000: 84 'T' 104 'h' 101 'e' 32 ' ' 112 'p' 114 'r' 111 'o' 99 'c' 0x804a008: 101 'e' 115 's' 115 's' 111 'o' 114 'r' 32 ' ' 86 'V' 101 'e' 0x804a010: 110 'n' 100 'd' 101 'e' 114 'r' 32 ' ' 73 'I' 68 'D' 32 ' ' 0x804a018: 105 'i' 115 's' 32 ' ' 39 '\'' 120 'x' 120 'x' 120 'x' 120 'x' 0x804a020: 120 'x' 120 'x' 120 'x' 120 'x' 120 'x' 120 'x' 120 'x' 120 'x' 0x804a028: 39 '\'' 10 '\n' (gdb)
我们用字符形式显示了 output 标签所在的内存地址前42个字节的内容, & 符号用于表明他是一个内存地址.
网友评论