Chinaunix首页 | 论坛 | 博客
  • 博客访问: 155969
  • 博文数量: 24
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 225
  • 用 户 组: 普通用户
  • 注册时间: 2014-08-09 13:04
个人简介

人若是没有理想,那跟咸鱼有什么区别!

文章分类

全部博文(24)

文章存档

2018年(1)

2017年(2)

2016年(8)

2015年(11)

2014年(2)

我的朋友

分类: LINUX

2016-02-27 18:55:06

1.从C到汇编的转变。
    先编写一个简单的C程序,main.c, 源码内容如下:

点击(此处)折叠或打开

  1. #include <stdio.h>

  2. int g(int a)
  3. {
  4.     return a + 3;
  5. }
  6. int main(int argc, char *argv[])
  7. {
  8.     return g(4);
  9. }
2.通过命令:gcc main.c -S -o main.s ,将源文件编译成 .S 文件。打开后内容如下:(以 . 开头的指令行为注释行,不参与实际的运行,为查看方便,已经去掉此内容)

点击(此处)折叠或打开

  1. g:
  2.     pushl    %ebp
  3.     movl    %esp, %ebp
  4.     movl    8(%ebp), %eax
  5.     addl    $3, %eax
  6.     popl    %ebp
  7.     ret
  8. main:
  9.     pushl    %ebp
  10.     movl    %esp, %ebp
  11.     subl    $4, %esp
  12.     movl    $4, (%esp)
  13.     call    g
  14.     leave
  15.     ret
3.指令执行分析:
a.在此先将列出几个特殊指令的形态:(栈空间由高地址向低地址增长)
    pushl %eax :  subl $4, %esp   ;    movl %eax, %(%esp);    #将eax寄存器的数进行压栈 ,esp下移4个字节,然后将eax的值赋给esp。
    popl %eax : movl (%esp), %eax    ;  subl %esp;    #将esp内的值赋给eax寄存器,同时将esp的指针上移四个字节。
    call 0x1234 : pushl %eip(*) ; movl 0x1234 , %eip(*); #将当前eip的值压栈,然后将新的入口地址0x1234放入eip寄存器中。
    ret  :  popl %eip(*);        #将下一行要处理的指令行号送入eip寄存器中。
    enter     :   pushl %ebp; movl %esp, %ebp ;   #将栈基指针压栈,然后将栈顶指针赋给栈基指针。
    leave    :    movl %ebp,%esp ;  popl %ebp ;    #这个跟enter正好相反。
b.程序的入口函数是main,在汇编代码中行号为 8. 第9/10行就是上面写的enter指令,这时重新构造了空栈,esp == ebp。

点击(此处)折叠或打开

  1. subl    $4, %esp
  2. movl    $4, (%esp)
    这两句先将esp 向下增长4个字节,然后将立即数4 赋给当前的esp。

点击(此处)折叠或打开

  1. call    g
      调用call时,eip指向的是下一条指令,行号为14. call指令会将eip进行压栈,然后将g 的行号放到eip中。此后程序会进入到g 函数中继续执行。
       第2/3 行进行构造栈。

      下一步中第4/5/6行进行对eax赋值。

点击(此处)折叠或打开

  1. movl    8(%ebp), %eax            #将ebp 地址加8 ,也就是movl $4, (%esp) 指令的 4 取出,放入eax中
  2. addl    $3, %eax                # 将3 加到eax中,此时eax值为7。
  3. popl    %ebp                    #将当前栈指针内容赋给ebp。
   
下一步第7行:

点击(此处)折叠或打开

  1. ret        #将下一行要处理的指令行号送入eip寄存器中。
下一步进入第14行,执行leave以及ret指令。清空当前栈。此时整个程序的返回值保存在eax中,结果为7。整个程序运行结束。


由上面的分析可以看出,整个汇编指令都是以流水线方式逐条进行处理,这也说明了cpu主频其实跟计算机的处理速度是有很大关联的。
作者程大鹏, 转载请注明出处    http://blog.chinaunix.net/blog/post.html
Linux内核分析》MOOC课程 ”



阅读(1893) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~