为了深入理解汇编程序中的帧指针(ebp)和栈指针(esp)的用法,想亲自调试下程序,我写了一个简单的程序,如下: #include <stdio.h> int add (int a, int b, int c); int main (int *argc, char *argv[]) { int a = 3; int b = 4; int c = 5; add (a, b, c); return 0; } int add (int a, int b, int c) { return a + b + c; }
保存为hello.c,然后在终端输入gcc -S hello.c,就会有个hello.s生成,也就是上面程序对应的汇编程序了,主要程序清单如下:
_start: //这里将main改成了_start,否则gdb找不到入口点 //另外加了一个nop,可以让程序在这里断下来 nop leal 4(%esp), %ecx andl $-16, %esp pushl -4(%ecx) pushl %ebp movl %esp, %ebp pushl %ecx subl $36, %esp movl $3, -16(%ebp) movl $4, -12(%ebp) movl $5, -8(%ebp) movl -8(%ebp), %eax movl %eax, 8(%esp) movl -12(%ebp), %eax movl %eax, 4(%esp) movl -16(%ebp), %eax movl %eax, (%esp) call add movl $0, %eax addl $36, %esp popl %ecx popl %ebp leal -4(%ecx), %esp ret .size main, .-main .globl add .type add, @function add: pushl %ebp movl %esp, %ebp movl 12(%ebp), %edx movl 8(%ebp), %eax addl %edx, %eax addl 16(%ebp), %eax popl %ebp ret
然后使用as -gstabs -o hello.o hello.s和ld -o hello hello.o生成可执行文件,最后就可以调试了,这里就是本文的重点了。
一、设断点
break *_start + 1,程序会在nop那里停下来
二、run
三、我调试的每一步
Breakpoint 1, _start () at hello.s:7
7 leal 4(%esp), %ecx
(gdb) info registers eax 0x0 0 ecx 0x0 0 edx 0x0 0 ebx 0x0 0 esp 0xbffff5c0 0xbffff5c0 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048095 0x8048095 <_start+1> eflags 0x200292 [ AF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
8 andl $-16, %esp
(gdb) info registers //查看寄存器,果然ecx = esp + 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff5c0 0xbffff5c0 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x8048099 0x8048099 <_start+5> eflags 0x200292 [ AF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
然后的这句话比较费解 andl %-16, %esp,-16的二进制表示为0xFFFFFFF0,这里是将SP的低4位清零了,这样地址就是16的整数倍了,寻址会更快,因为esp的低4位本身就是0,所以这句话在这里并没有起到作用,我们就把这里跳过,直接next
(gdb) next
9 pushl -4(%ecx)
(gdb) next
10 pushl %ebp
(gdb) info registers //pushl -4(%ecx) ,把ecx压栈,esp -= 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff5bc 0xbffff5bc ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x804809f 0x804809f <_start+11> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
11 movl %esp, %ebp
(gdb) info registers // pushl %ebp,ebp压栈,esp -= 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff5b8 0xbffff5b8 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x80480a0 0x80480a0 <_start+12> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
_start () at hello.s:12
12 pushl %ecx
(gdb) info registers //movl %esp, %ebp, ebp = esp eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff5b8 0xbffff5b8 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480a2 0x80480a2 <_start+14> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
13 subl $36, %esp
(gdb) info registers //pushl %ecx, ecx压栈, esp -= 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff5b4 0xbffff5b4 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480a3 0x80480a3 <_start+15> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
14 movl $3, -16(%ebp)
(gdb) info registers //subl $36, %esp,esp -= 36,分配36个字节的空间 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480a6 0x80480a6 <_start+18> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
15 movl $4, -12(%ebp)
(gdb) info registers //movl $3, -16(%ebp), *(ebp - 16) = 3 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480ad 0x80480ad <_start+25> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
16 movl $5, -8(%ebp)
(gdb) info registers //movl $4, -12(%ebp), *(ebp - 12) = 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480b4 0x80480b4 <_start+32> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
17 movl -8(%ebp), %eax
(gdb) info registers //movl $5, -8(%ebp), *(ebp -8) = 5 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480bb 0x80480bb <_start+39> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
3, 4, 5就分别存放到了ebp -16, ebp -12, ebp -8 这3个位置
我们查看下是不是这样的
(gdb) x /4 0xbffff5a8 //果然在
0xbffff5a8: 3 4 5 -1073744444
(gdb) next
18 movl %eax, 8(%esp)
(gdb) info registers //movl -8(%ebp), %eax, eax = *(ebp - 8) eax 0x5 5 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480be 0x80480be <_start+42> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
19 movl -12(%ebp), %eax
(gdb) info registers //mov %eax, 8(%esp), *(esp + 8) = eax eax 0x5 5 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480c2 0x80480c2 <_start+46> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
20 movl %eax, 4(%esp)
(gdb) info registers //movl -12(%ebp), %eax, eax = *(ebp - 12) eax 0x4 4 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480c5 0x80480c5 <_start+49> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
21 movl -16(%ebp), %eax
(gdb) info registers //movl %eax, 4(%esp), *(esp + 4) = eax eax 0x4 4 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480c9 0x80480c9 <_start+53> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
22 movl %eax, (%esp)
(gdb) info registers //movl -16(%ebp), %eax, eax = *(ebp - 16) eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480cc 0x80480cc <_start+56> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
23 call add
(gdb) info registers //movl %eax, (%esp), *esp = %eax eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480cf 0x80480cf <_start+59> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) step
add () at hello.s:34
34 pushl %ebp
(gdb) info registers //这里进入了add函数,esp会将函数的返回地址压栈,esp -= 4 eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff58c 0xbffff58c ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480e2 0x80480e2 <add> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
35 movl %esp, %ebp
(gdb) info registers //pushl %ebp,ebp压栈,esp -= 4 eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff588 0xbffff588 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480e3 0x80480e3 <add+1> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
36 movl 12(%ebp), %edx
(gdb) info registers //movl %esp, %ebp, ebp = esp eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x0 0 ebx 0x0 0 esp 0xbffff588 0xbffff588 ebp 0xbffff588 0xbffff588 esi 0x0 0 edi 0x0 0 eip 0x80480e5 0x80480e5 <add+3> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
37 movl 8(%ebp), %eax
(gdb) info registers //movl 12(%ebp), %edx, edx = *(ebp + 12) eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff588 0xbffff588 ebp 0xbffff588 0xbffff588 esi 0x0 0 edi 0x0 0 eip 0x80480e8 0x80480e8 <add+6> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
38 addl %edx, %eax
(gdb) info registers //movl 8(%ebp), %eax,eax = *(ebp + 8) eax 0x3 3 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff588 0xbffff588 ebp 0xbffff588 0xbffff588 esi 0x0 0 edi 0x0 0 eip 0x80480eb 0x80480eb <add+9> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
39 addl 16(%ebp), %eax
(gdb) x /4 0xbffff590 0xbffff590: 3 4 5 0 (gdb) info registers //addl %edx, %eax, eax = eax + edx eax 0x7 7 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff588 0xbffff588 ebp 0xbffff588 0xbffff588 esi 0x0 0 edi 0x0 0 eip 0x80480ed 0x80480ed <add+11> eflags 0x200202 [ IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
40 popl %ebp
(gdb) info registers //addl 16(%ebp), %eax, eax += *(ebp + 16) eax 0xc 12 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff588 0xbffff588 ebp 0xbffff588 0xbffff588 esi 0x0 0 edi 0x0 0 eip 0x80480f0 0x80480f0 <add+14> eflags 0x200206 [ PF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
add () at hello.s:41
41 ret
(gdb) info registers //popl %ebp ,ebp出栈, esp += 4 eax 0xc 12 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff58c 0xbffff58c ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480f1 0x80480f1 <add+15> eflags 0x200206 [ PF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
_start () at hello.s:24
24 movl $0, %eax
(gdb) info registers //ret , esp += 4, 函数返回地址出栈 eax 0xc 12 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480d4 0x80480d4 <_start+64> eflags 0x200206 [ PF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
25 addl $36, %esp
(gdb) info registers //movl $0, %eax, eax = 0 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff590 0xbffff590 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480d9 0x80480d9 <_start+69> eflags 0x200206 [ PF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
26 popl %ecx
(gdb) info registers //addl $36, %esp , esp += 36,释放36个字节 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff5b4 0xbffff5b4 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480dc 0x80480dc <_start+72> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
27 popl %ebp
(gdb) info registers //popl %ecx , esp += 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff5b8 0xbffff5b8 ebp 0xbffff5b8 0xbffff5b8 esi 0x0 0 edi 0x0 0 eip 0x80480dd 0x80480dd <_start+73> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
_start () at hello.s:28
28 leal -4(%ecx), %esp
(gdb) info registers //popl %ebp, esp += 4 eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff5bc 0xbffff5bc ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x80480de 0x80480de <_start+74> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
_start () at hello.s:29
29 ret
(gdb) info registers //esp = *(ecx - 4) eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff5c0 0xbffff5c0 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x80480e1 0x80480e1 <_start+77> eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
(gdb) next
0x00000001 in ?? ()
(gdb) info registers eax 0x0 0 ecx 0xbffff5c4 -1073744444 edx 0x4 4 ebx 0x0 0 esp 0xbffff5c4 0xbffff5c4 ebp 0x0 0x0 esi 0x0 0 edi 0x0 0 eip 0x1 0x1 eflags 0x200286 [ PF SF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x0 0
程序结束