运行下面几行代码时,发现结果有点奇怪,就反汇编看了一下,顺便记录一下在linux中 调试的命令。
#include <stdio.h>
int main()// 数组越界访问
{
int test[2];
int i;
for(i = 0; i < 3; i++)
{
test[i] = 1;
printf("%d\n", test[i]);
}
return 0;
}
gcc main.c -o main
./main
运行结果为死循环打印1
lnx@lnx-pc:/mnt/hgfs/share/leetcode/mbstowcs$ gcc -g main2.c
lnx@lnx-pc:/mnt/hgfs/share/leetcode/mbstowcs$ objdump -S a.out > main.s
反汇编代码如下,只看一下main函数部分:
080483e4 <main>:
#include <stdio.h>
int main()// 数组越界访问
{
80483e4: 55 push %ebp// ebp寄存器内容压栈,即保存main函数的上级调用函数的栈基地址
80483e5: 89 e5 mov %esp,%ebp// esp值赋给ebp,设置main函数的栈基址
80483e7: 83 e4 f0 and $0xfffffff0,%esp// 使栈地址16字节对齐
80483ea: 83 ec 20 sub $0x20,%esp// 通过ESP-8来分配8字节堆栈空间
int test[2];
int i;
for(i = 0; i < 3; i++)
80483ed: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
80483f4: 00
80483f5: eb 2a jmp 8048421 <main+0x3d>
{
test[i] = 1;
80483f7: 8b 44 24 1c mov 0x1c(%esp),%eax
80483fb: c7 44 84 14 01 00 00 movl $0x1,0x14(%esp,%eax,4)
8048402: 00
printf("%d\n", test[i]);
8048403: 8b 44 24 1c mov 0x1c(%esp),%eax
8048407: 8b 54 84 14 mov 0x14(%esp,%eax,4),%edx
804840b: b8 f0 84 04 08 mov $0x80484f0,%eax
8048410: 89 54 24 04 mov %edx,0x4(%esp)
8048414: 89 04 24 mov %eax,(%esp)
8048417: e8 00 ff ff ff call 804831c <printf@plt>
#include <stdio.h>
int main()// 数组越界访问
{
int test[2];
int i;
for(i = 0; i < 3; i++)
804841c: 83 44 24 1c 01 addl $0x1,0x1c(%esp)
8048421: 83 7c 24 1c 02 cmpl $0x2,0x1c(%esp)
8048426: 7e cf jle 80483f7 <main+0x13>
{
test[i] = 1;
printf("%d\n", test[i]);
}
return 0;
8048428: b8 00 00 00 00 mov $0x0,%eax// 设置main函数返回值
804842d: c9 leave// 撤销Stack Frame(栈框架)
804842e: c3 ret// main 函数返回
804842f: 90 nop
接下来使用gdb调试:
lnx@lnx-pc:/mnt/hgfs/share/leetcode/mbstowcs$ gdb a.out
GNU gdb (GDB) 7.1-ubuntu
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 "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /mnt/hgfs/share/leetcode/mbstowcs/a.out...done.
(gdb) l
1 #include <stdio.h>
2 int main()// 数组越界访问
3 {
4 int test[2];
5 int i;
6 for(i = 0; i < 3; i++)
7 {
8 test[i] = 1;
9 printf("%d\n", test[i]);
10 }
(gdb) b 6// 设置断点
Breakpoint 1 at 0x80483ed: file main2.c, line 6.
(gdb) r
Starting program: /mnt/hgfs/share/leetcode/mbstowcs/a.out
Breakpoint 1, main () at main2.c:6
6 for(i = 0; i < 3; i++)
(gdb) i r// 显示寄存器当前值
eax 0xbffff3c4 -1073744956
ecx 0x4363b11d 1130606877
edx 0x1 1
ebx 0x283ff4 2637812
esp 0xbffff2f0 0xbffff2f0
ebp 0xbffff318 0xbffff318
esi 0x0 0
edi 0x0 0
eip 0x80483ed 0x80483ed <main+9>
eflags 0x286 [ PF SF IF ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51
(gdb) x/8xw 0xbffff2f0// 使用examine命令(简写是x)来查看内存地址中的值;8个单位;
// x指按十六进制格式显示变量;w指每单位4字节
0xbffff2f0: 0x00284324 0x00283ff4 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x0011e030 0x0804844b 0x00283ff4// esp到ebp的初始值为随机值
(gdb) s// 执行一行源程序代码,如果此行代码中有函数调用,则进入该函数;
// 这里执行的是i = 0,对应汇编代码为movl $0x0,0x1c(%esp)
8 test[i] = 1;
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x00284324 0x00283ff4 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x0011e030 0x0804844b 0x00000000// 0x1c(%esp)为0xbffff30c
(gdb) s
9 printf("%d\n", test[i]);// 前面执行的jmp 8048421 <main+0x3d>
// cmpl $0x2,0x1c(%esp)
// jle 80483f7 <main+0x13>
// 这里执行 mov 0x1c(%esp),%eax
// movl $0x1,0x14(%esp,%eax,4)
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x00284324 0x00283ff4 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x0804844b 0x00000000
(gdb) s
1// 打印1mov 0x1c(%esp),%eax
// mov 0x14(%esp,%eax,4),%edx
// mov $0x80484f0,%eax
// mov %edx,0x4(%esp)
// mov %eax,(%esp)
// call 804831c <printf@plt>
6 for(i = 0; i < 3; i++)
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x0804844b 0x00000000
(gdb) s
8 test[i] = 1;// addl $0x1,0x1c(%esp)
// cmpl $0x2,0x1c(%esp)
// jle 80483f7 <main+0x13>
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x0804844b 0x00000001
(gdb) s
9 printf("%d\n", test[i]);// mov 0x1c(%esp),%eax
// movl $0x1,0x14(%esp,%eax,4)
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000001
(gdb) s
1
6 for(i = 0; i < 3; i++)
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000001
(gdb) s
8 test[i] = 1;// 直到这里i的值为2
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000002
(gdb) s
9 printf("%d\n", test[i]);// mov 0x1c(%esp),%eax// %eax的值为2
// movl $0x1,0x14(%esp,%eax,4)// 0x14(%esp,%eax,4)的值为0xbffff30c
// 与i的地址相同,所以i的值被修改为1
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000001
(gdb) s
1
6 for(i = 0; i < 3; i++)
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000001
(gdb) s
8 test[i] = 1;// i=2,test[2] = 1,i的值再被修改为1,形成死循环
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000002
(gdb) s
9 printf("%d\n", test[i]);
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000001
(gdb) s
1
6 for(i = 0; i < 3; i++)
(gdb) x/8xw 0xbffff2f0
0xbffff2f0: 0x080484f0 0x00000001 0x08048440 0xbffff318
0xbffff300: 0x0015d4a5 0x00000001 0x00000001 0x00000001
(gdb)