反汇编C程序
目录
- 反汇编源程序
- 分析汇编过程
- 问题与总结
- 参考链接
一、反汇编源程序
对于这样一个源程序:
// main.c
int g(int x)
{
return x + 2;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(4) + 3;
}
通过命令gcc –S main.c –o main.s -m32
将main.c编译成汇编代码,得到如图的汇编代码文件main.s:
通过g/\.s*/d
去掉多余辅助信息:
得到可供分析的汇编代码:
二、分析汇编过程
对如下的汇编代码进行分析:
1 g:
2 pushl %ebp
3 movl %esp, %ebp
4 movl 8(%ebp), %eax
5 addl $2, %eax
6 popl %ebp
7 ret
8 f:
9 pushl %ebp
10 movl %esp, %ebp
11 pushl 8(%ebp)
12 call g
13 addl $4, %esp
14 leave
15 ret
16 main:
17 pushl %ebp
18 movl %esp, %ebp
19 pushl $4
20 call f
21 addl $4, %esp
22 addl $3, %eax
23 leave
24 ret
初始时栈的状态如下:
从main函数开始执行,首先执行17 pushl %ebp
,esp沿着地址递减的方向指向下一个存储单元,将ebp现在指向的存储单元的地址压入栈中,即将2000入栈
执行18 movl %esp, %ebp
,将ebp移动至esp所指的存储单元
执行19 pushl $4
,将参数4压入栈中
执行20 call f
,调用f函数,相当于将下一条指令的地址,即EIP中的值21压入栈中,并将f函数的第一条指令的地址9存入EIP当中,表示下一条执行的指令在第9行
执行9 pushl %ebp
,将ebp指向的存储单元的地址1996入栈
执行10 movl %esp, %ebp
,将ebp移动至esp所指的存储单元
执行11 pushl 8(%ebp)
,相当于ebp沿地址递增的方向移动两个存储单元,将其中存储的数据压入栈中,即将4入栈
执行12 call g
,调用g函数,将当前EIP中的值13入栈,将g函数的第一条指令地址2存入EIP寄存器中,下一条执行的指令在第2行
执行2 pushl %ebp
,将ebp指向的存储单元的地址1984入栈
执行3 movl %esp, %ebp
,将ebp移动至esp所指的存储单元
执行4 movl 8(%ebp), %eax
,相当于ebp沿地址递增的方向移动两个存储单元,将其中存储的数据4存入EAX寄存器中
执行5 addl $2, %eax
,将EAX寄存器中的值加2,结果为6
执行6 popl %ebp
,将当前栈顶的值1984弹出栈,并将esp移动至地址为1984的存储单元,esp沿地址递增的方向移动一个存储单元
执行7 ret
,将当前栈顶的值13弹出栈,并存入EIP当中,下一条执行的指令地址为13
执行13 addl $4, %esp
,将esp沿着地址递增的方向移动一个存储单元
执行14 leave
,将栈顶的值1996弹出至ebp,即将ebp移动至地址为1996的存储单元,esp沿地址递增的方向移动一个存储单元
执行15 ret
,将当前栈顶的值21弹出至EIP寄存器中,即下一条执行的指令在第21行
执行21 addl $4, %esp
,将esp沿着地址递增的方向移动一个存储单元
执行22 addl $3, %eax
,将EAX寄存器中的值加3,结果为9
执行23 leave
,将当前栈顶的值2000弹出栈,将ebp移动至地址为2000的存储单元,同时将esp沿地址递增的方向移动一个存储单元。此时堆栈空间回到了main函数执行前的状态,恢复至空栈。
执行24 ret
,执行完毕。
三、问题与总结
阅读《庖丁解牛Linux内核分析》第一章之后,对计算机的工作方式有了更深的了解,对于汇编代码的执行过程和堆栈空间有了进一步的理解和认识。在第一次尝试对汇编代码进行分析时,由于对汇编语言的了解不够深入,导致最开始的分析过程进入了误区。
问题:在执行指令movl 8(%ebp), %eax
时,ebp指针是否进行了移动?
这条指令的意思是:将地址[ebp+8]指向的数据存入eax寄存器中。所以我个人的理解是在ebp的基础上进行地址计算,将加8之后的地址所指向的数据存入eax中,ebp应该是不动的。
最后对计算机的工作方式进行一个总结:由于计算机的指令与数据都保存在内存中,因此当计算机开始工作时,通过控制器在内存中取出指令,根据指令的内容要求,从内存中取出数据并进行指定的运算或逻辑操作,再将结果送入内存中的指定地址中。随着程序的编排,计算机将指令逐条取出,自动完成一条条指令所规定的操作,直至遇到停止指令。