2020-2021-1 20209315《Linux内核原理与分析》第二周作业

实验部分:

反汇编一个简单的C程序

        开始程序的编写,创建一个main.c文件,打开main.c文件在其中输入一个简单的c程序,并进行保存。

 

        程序如下图所示:

 

 

        程序编写完成后,对main.c文件进行编译,会自动生成一个目标文件a.out。

        执行a.out文件,此处无输出。

        利用如下指令可以将main.c编译成一个汇编代码,给这个汇编代码起名main.s。

        打开mian.s文件 ,可以看到上面所写的c程序相应的汇编代码:

        函数g的汇编部分:

        函数f的汇编部分:

 

         main函数:

 其中的重要指令有:pushl/pop和call/ret。此处的pushl表示32位的push.

 

pushl %eax

 

就是将EAX寄存器寄存器的值压到堆栈栈顶,实际上分为两个动作,其中一个为:

 

subl $4 %esp

 

把堆栈的栈顶ESP寄存器的值减4,因为堆栈是向下增长的,所以用subl减指令,在堆栈栈顶留出一个存储单元给要存进来的值,第二个动作为:

 

movl %eax, (%esp)

 

 把ESP存储器加一个小括号(间接寻址),就是把EAX寄存器的值放到ESP寄存器所指向的地方,这时ESP寄存器已经指向预留出的存储单元。

接下来介绍popl指令,如:


popl %eax


就是从堆栈的栈顶取一个存储单元(32位数值),从堆线枝顶的位置放到EAX寄存器里,这称为出栈。出栈同样对应两个操作:


movl (%esp) ,%eax

addl $4 , %esp


第一步是把栈顶的数值放到EAX寄存器里,然后用指令addl把栈顶加4,相当于栈向上回退了一个存储单元的位置,也就是栈在收缩。每次执行指令pushl 栈都在增长,执行指令popl栈都在收缩。

汇编程序中main函数的执行过程:

 

 

 

 

        程序从main函数开始执行,也就是“"main:" 下面的第一 条指令“pushl %ebp”,这是开始执行的第一 条指令,这条指令的作用实际上就是把EBP寄存器的值压栈,pushl指令的功能是先把ESP寄存器指向标号1的位置,即标号加1或地址减4 (向下移动4个字节),然后将EBP寄存器的值标号0 (地址2000) 放到堆栈标号1的位置。。

 

       开始执行上一条指令时,EIP寄存器已经自动加1指向了“movl%esp,%ebp",是将EBP寄存器也指向标号1 的位置,这条语句只修改了EBP寄存器, 栈空间的内容并没有变化。第18行和第19行语句是建立main函数自己的函数调用堆栈空间。

 

       开始执行上一条指令时,EIP寄存器已经自动加1指向了“subl $4,%esp”,把ESP寄存器减4,实际上是ESP寄存器向下移动一个标号,指向标号2的位置。这条语句只修改了ESP寄存器,栈空间的内容并没有变化。

       开始执行上一条指令时,EIP 寄存器已经自动加1指向了“movI $8, (%esp)”,把立即数8放入ESP寄存器指向的标号2位置,也就是"subl $4,%esp"预留出来的标号2的位置。这条语句的EBP和ESP寄存器没有变化,栈空间发生了变化。这两个语句是在为接下来调用f函数做准备,即压栈f函数所需的参数。

      开始执行上一条指令时; EIP寄存器已经自动加1指向了指令"call f", call 指令相当于如下两条伪指令:

           pushl %eip(*)

           movl f %eip(*)

       "call f"开始执行时,EIP 寄存器已经自加1指向了下一.条指令,实际上把EIP寄存器的值放到了栈空间标号3的位置。因为压栈前ESP寄存器的值是标号2,压栈时ESP寄存器先减4个字节,即指向下一个位置标号3,然后将EIP寄存器的行号23入栈到栈空间标号3的位置。接着将f函数的第一条指令的行号9放入EIP寄存器,这样EIP寄存器指向了f函数。这条语句既改变了栈空间,又改变了ESP寄存器,更重要的是它改变了EIP寄存器。原来EIP寄存器自加1指令是按顺序执行的,现在EIP寄存器跳转到了f函数的位置。

 

posted @ 2020-10-13 20:10  20209315  阅读(195)  评论(0编辑  收藏  举报