GCC编译
-
安装库,使用sudo apt-get install libc6-dev-i386命令。
-
然后执行命令gcc -g code.c -o code -m32命令就可以在64位的机器上生成32位汇编代码
分析过程
- 使用gdb调试代码。
- 使用break main指令在main函数处设置断点,然后调试,直到mian函数处。
- 使用diassemble指令获取汇编代码
依次如下指令调试汇编代码,并查看%esp、%ebp和堆栈内容:
1、使用si指令单步跟踪一条机器指令
2、使用i r指令查看各寄存器的值(在这里要看%eip、%eax、%esp和%ebp)
3、使用x/na %esp对应的值指令查看堆栈变化
代码分析
指令 |
%eip |
%esp |
%ebp |
%eax |
堆栈 |
push $0x8 |
0x804840b |
0xffffd588 |
0xffffd588 |
0xf7fbadbc |
0x0 |
call 0x80483ef |
0x804840d |
0xffffd584 |
0xffffd588 |
0xf7fbadbc |
0x8 0x0 |
push %ebp |
0x80483ef |
0xffffd580 |
0xffffd588 |
0xf7fbadbc |
0x8048412 0x8 0x0 |
mov %esp,%ebp |
0x80483f0 |
0xffffd57c |
0xffffd588 |
0xf7fbadbc |
0xffffd588 0x8048412 0x8 0x0 |
mov 0x804a01c,%edx |
0x80483f2 |
0xffffd57c |
0xffffd57c |
0xf7fbadbc |
0xffffd588 0x8048412 0x8 0x0 |
0x8(%ebp),%eax |
0x80483f8 |
0xffffd57c |
0xffffd57c |
0xf7fbadbc |
0xffffd588 0x8048412 0x8 0x0 |
Add %edx,%eax |
0x80483fb |
0xffffd57c |
0xffffd57c |
0x8 |
0xffffd588 0x8048412 0x8 0x0 |
Push %eax |
0x80483fd |
0xffffd57c |
0xffffd57c |
0xa |
0xffffd588 0x8048412 0x8 0x0 |
Call 0x80483db |
0x80483fe |
0xffffd578 |
0xffffd57c |
0xa |
0xa 0xffffd588 0x8048412 0x8 0x0 |
Push%ebp |
0x80483db |
0xffffd574 |
0xffffd57c |
0xa |
0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
Mov %esp,%ebp |
0x80483dc |
0xffffd570 |
0xffffd57c |
0xa |
0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
Movzwl 0x804a018,%eax |
0x80483de |
0xffffd570 |
0xffffd570 |
0xa |
0xffffd570 0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
Movswl %ax,%edx |
0x80483e5 |
0xffffd570 |
0xffffd570 |
0x1 |
0xffffd570 0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
mov 0x8(%ebp),%eax |
0x80483e8 |
0xffffd570 |
0xffffd570 |
0x1 |
0xffffd570 0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
Add %edx,%eax |
0x80483eb |
0xffffd570 |
0xffffd570 |
0xa |
0xffffd570 0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
Pop %ebp |
0x80483ed |
0xffffd570 |
0xffffd570 |
0xb |
0xffffd570 0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
ret |
0x80483ee |
0xffffd574 |
0xffffd57c |
0xb |
0x8048403 0xa 0xffffd588 0x8048412 0x8 0x0 |
Add $0x4,%esp |
0x8048403 |
0xffffd578 |
0xffffd57c |
0xb |
0xa 0xffffd588 0x8048412 0x8 0x0 |
leave |
0x8048406 |
0xffffd57c |
0xffffd57c |
0xb |
0xffffd588 0x8048412 0x8 0x0 |
ret |
0x8048407 |
0xffffd580 |
0xffffd588 |
0xb |
0x8048412 0x8 0x0 |
Add $0x4,%esp |
0x8048412 |
0xffffd584 |
0xffffd588 |
0xb |
0x8 0x0 |
Mov $0x3,edx |
0x8048415 |
0xffffd588 |
0xffffd588 |
0xb |
0x0 |
Add %edx,%eax |
0x804841a |
0xffffd588 |
0xffffd588 |
0xb |
0x0 |
leave |
0x804841c |
0xffffd588 |
0xffffd588 |
0xe |
0x0 |
ret |
0x804841d |
0xffffd58c |
0x0 |
0xe |
在这里我对实验楼中的课后练习题的代码进行了分析:
int g(int x)
{
return x + 3;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(8) + 1;
}
汇编代码及分析:
g:
pushl %ebp // 将%ebp入栈
movl %esp, %ebp // esp指向ebp
movl 8(%ebp), %eax //把保存在%ebp+8处的值x传送给%eax
addl $3, %eax //执行语句x+3,将结果返回给%eax
popl %ebp //弹出%ebp的值
ret
f:
pushl %ebp //将ebp入栈
movl %esp, %ebp //esp指向ebp
subl $4, %esp //esp+4
movl 8(%ebp), %eax //将%ebp+8位置的值保存给%eax
movl %eax, (%esp) //将eax的值给esp所值的位置
call g //调用g函数,将返回地址压入栈中,然后调到函数g的第一条指令
leave //为返回准备栈
ret
main: //主函数
pushl %ebp //将ebp入栈
movl %esp, %ebp //esp指向ebp
subl $4, %esp //esp+4
movl $8, (%esp) //将8给esp所指的地址
call f //调用f函数,将返回地址压入栈中,然后调到函数f的第一条指令
addl $1, %eax //执行表达式return f(8)+1,将%eax中的值加一再返回
leave
ret
代码调试中的问题
使用gcc -g code.c -o code -m32命令时,如果系统提示以下错误:
是因为虚拟机缺少了一个库,使用命令sudo apt-get install libc6-dev-i386进行安装就行了。