本周我通过学习《Linux内核分析配套实验》课程的实验1,通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的。
步骤一
在实验楼中,新建main.c,输入以下代码:
?
步骤二
输入gcc -S -o main.s main.c -m32.将此程序反汇编成汇编程序.
其中:-S表示执行反汇编,-m32表示转换成32位汇编程序。
注意实验楼的实验环境是64位,所以这里要加-m32。
?
?步骤三
使用命令:gedit main.s 查看汇编程序。???
?实验分析:
我们会发现,简短的几句c语言,转换成汇编代码如此复杂,通过学习,我了解到汇编程序中只要是以“.”开头的语句,例如“.globl g”,都是用于链接辅助信息,实际并不会执行,所以在进行代码分析时可以直接忽略这些语句。简化后的代码如下所示:
g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $3, %eax
popl %ebp
ret
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $9, (%esp)
call f
addl $1, %eax
leave
ret
我们会发现,此汇编程序和c语言程序一样,也分为三部分:f 函数 、g 函数、main主函数
首先执行的是main函数:
pushl?? %ebp?
movl??? %esp, %ebp
?BP:堆栈基指针? ? ? SP:堆栈顶指针
这两句的指令是保存栈基指针BP的内容,然后把栈顶指针SP拷贝给栈基指针BP。
?
subl??? $4, %esp????
movl??? $9, (%esp)
第一条指令的是栈顶指针往下移4个单位,分配了一个单元。第二条指令将数值9存储到刚刚分配的个单元中。所以这两条指令的作用是将数值9压入堆栈。
接下来是call f 即调用f函数,这时我们来看f函数。??前三句和main函数的前三句相同故此不重复进行分析,第四句如下:
movl??? 8(%ebp), %eax??
movl %eax, (%esp)
它的含义是将栈基指针的内容加上8对应的存储单元的内容传送给累加寄存器EAX。下一条指令再把EAX内容拷贝给栈顶指针所指的位置。
call g
这条指令是调用g函数。? ?g函数中前两条指令和main函数中的前两条指令作用一样,便不再赘述。
movl 8(%ebp), %eax
addl $6, %eax
第一条指令的含义是将栈基指针的内容加上8对应的存储单元的内容传送给累加寄存器EAX。第二条指令将数值6加到累加寄存器EAX中。
popl %ebp
这条指令相当于:movl (%esp),%ebp?? add $4,%esp。实现将之前压入栈的栈基指针EBP的内容出栈到EBP中。最后g 函数中的ret指令相当于c语言中的return返回程序运行值,最后回到main函数 顺序执行到此指令:
addl $1, %eax
这条指令是将数值1加到累加寄存器EAX中
leave
ret
最后leave是撤销函数堆栈,ret相当于c语言中的return返回程序运行值。
总结
????????通过本周对于计算机汇编的基础知识的学习,以及实验楼的实验一的完成,我对于计算机的基本原理存储程序有了更加深刻的认知,简短的几句c语言程序,转换成对应的汇编代码便复杂了很多,对于计算机而言,原始的数据需要通过输入设备输入到计算机的存储器中,然后通过指令,进行运算。在汇编程序中,便体现在通过指令,利用寄存器存储值,只要利用栈这一结构来实现了函数之间的调用、最后实现结果。
|