网易云课堂linux内核分析(一)

这是网易云课堂linux内核分析课程的实验报告linux

实验的内容是经过编写一段简单的c程序,并分析其汇编代码,以了解计算机是如何运行程序。vim

程序hello.c源代码:bash

1 #include <stdio.h>
  2 
  3 int bar(int a)
  4 {
  5     return a;
  6 }
  7 
  8 int foo(a)
  9 { 
 10     return bar(a) + 1;
 11 }
 12 
 13 int main()
 14 {
 15     return foo(10) + 1;
 16 }

在bash下输入以下指令,得到源代码的汇编hello.s:函数

gcc -S -o hello.s hello.c -m32

因为本次试验只须要用到源代码对应的汇编指令,因此能够把hello.s中以.开头的行删除。在vim下可使用:spa

:%s/\s*\..*//g     #将以"."开头的行换为空行
:%g/^$/d           #删除空行

操做后获得如下代码:code

1 bar:
  2     pushl   %ebp
  3     movl    %esp, %ebp
  4     movl    8(%ebp), %eax
  5     popl    %ebp
  6     ret
  7 foo:
  8     pushl   %ebp
  9     movl    %esp, %ebp
 10     subl    $4, %esp
 11     movl    8(%ebp), %eax
 12     movl    %eax, (%esp)
 13     call    bar
 14     addl    $1, %eax
 15     leave
 16     ret
 17 main:
 18     pushl   %ebp
 19     movl    %esp, %ebp
 20     subl    $4, %esp
 21     movl    $10, (%esp)
 22     call    foo
 23     addl    $1, %eax
 24     leave
 25     ret

下面对汇编代码进行分析,从main函数开始:
1八、19行的pushlmovl指令至关于enter指令,用于保存前一个栈的信息,同时为main函数开辟一个空栈。pushl将前一个栈的基地址保存,movlebp赋值为前一个栈的栈顶,同时也是main栈的基地址。esp做为main栈的栈顶。完成了上面两部,main栈就算建成了。接下来开始执行源代码里的东西了。ip

20、21行。subl为函数的栈开了空间,用来存放foo须要的参数。movl将参数放在该空间。而后执行call指令,跳到foo函数中,也就是eip要变成foo的地址。注意call指令要把当前eip压栈(pushl %eip)。而后把目光转到foo函数中,也就是第7行。和main函数开头同样,须要保存上一个栈的信息,同时为本身开创一个栈。pushlmovl指令作了这件事。接着放置bar须要的参数在本身的栈中(就是刚刚在mian函数时放的那个参数)。完成后执行call指令跳到bar函数。内存

bar函数终于再也不调用别的函数,而是获取foo给的参数(第4行,这时候ebp就是foo栈的栈顶)。将参数赋值给eax后进行结束函数的工做。第5行的popl指令将esp加4,变为前一个栈(foo)的栈顶;ebp得到出栈的内容,也就是前一个栈的基址。foo的栈完成恢复。最后ret指令跳回foo函数中(至关于popl %eip),bar函数就正式结束了。回到foo函数后,根据源代码要给返回值加1(14行),紧接着要结束foo。和结束bar函数过程同样,结束foo函数就是执行leave而后回跳到main中。main函数为返回值加1(23行),以一样的流程退出main函数。程序结束。get

注意1:函数的栈在内存中是从高地址向低地址增加的,因此pushlesp要减4,而poplesp要加4
注意2:leave指令至关于movl %esp %ebppopl %ebp
因为bar的代码没有使用到变量,因此在建立好函数的栈后,espebp是相等的,不须要leave指令。函数foo和main中建立了变量,并存放在栈中,修改了esp,所以退出函数时要还原esp的。因此在退出函数的时候要使用leave
注意3:call指令压栈的内容在调用函数的栈中。毕竟call指令执行在开辟新的函数栈指令以前。it

理解:
程序就是由一条条汇编代码组成。这些汇编代码执行了运算,使用了内存空间。c语言中的函数,就是汇编中将当前寄存器保存到内存中,而后转跳到另一处执行,执行完成后跳回原来地方,并恢复寄存器内容。而c语言屏蔽了这一过程,提供了抽象,咱们只须要专一于函数要实现什么功能,不须要关注如何实现函数。

过程截图
源代码和汇编

xxtsmooc
原创做品转载请注明出处
《Linux内核分析》MOOC课程
http://mooc.study.163.com/course/USTC-1000029000

相关文章
相关标签/搜索