zoukankan      html  css  js  c++  java
  • Linux内核分析第一周学习总结:计算机是如何工作的?

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

    一、冯诺依曼体系结构:存储程序计算机

    1. 从硬件角度

    	 	 总线				
    CPU	 ============	内存
    
    - CPU上的IP总指向内存的某一块区域,CPU执行其所指向的指令。
    

    2. 从程序员角度(软件)

    内存保存指令和数据,CPU解释执行
    
    • 接口
      • API:应用程序编程接口,程序员<->计算机
      • ABI:应用程序二进制接口,程序<->CPU

    二、汇编基础

    1. 寄存器

    • 通用寄存器
    通用寄存器
    16bit32bit
    AXeax累加器
    BXebx基址寄存器
    CXecx计数寄存器
    DXedx数据寄存器
    BPebp堆栈基址指针
    SIesi变址寄存器
    DIedi变址寄存器
    SPesp堆栈顶指针
    • 段寄存器
    段寄存器
    CS代码段
    BS数据段
    ES附加段
    SS堆栈段
    FS附加段
    GS附加段
    • CPU实际取指令的时候根据cs:eip来准确定位一个指令

    2. 几种寻址方式

    • 寄存器寻址(register)

        例:movl %eax,%edx  <=>  edx=eax
      
    • 立即数寻址(immediate)

        例:movl $0x123,%edx  <=>  edx=0x123
      
    • 直接寻址(direct)

        例:movl 0x123,%edx  <=>  edx=*(int32_t*)0x123
      
    • 间接寻址(indirect)

        例:movl (%ebx),%edx  <=>  edx=*(int32_t*)ebx
      
    • 变址寻址(displaced)

        例:movl 4(%ebx),%edx  <=>  edx=*(int32_t*)(ebx+4)
      
    • 注:Linux内核使用A&T汇编格式(另有Intel汇编格式)

    3. 常见指令

    • pushl %eax:

        subl $4,%esp
        movl %eax,(%esp)
      
    • popl %eax:

        movl (%esp),%eax
        addl $4,%esp
      
    • call 0x12345:

        pushl %eip (*)
        movl $0x12345,%eip (*)
      
    • ret:

        popl %eip (*)
      
    • enter:

        pushl %ebp
        movl %esp,%ebp
      
    • leave

        movl %ebp,%esp
        popl %ebp
      
    • 注:由于eip不能被程序员直接修改,所以(*)不能直接使用。

    • 函数调用堆栈是由逻辑上多个堆栈叠加起来的。

    • ebp和esp这两个寄存器总是指向堆栈的栈底和栈顶,这里所说的是相对的概念。

    • 函数返回值默认存储在%eax寄存器中。

    二、汇编代码的分析

    1. main.c代码

    2. 汇编代码

    gcc -S -o main.S main.c -m32
    
    -S:仅汇编
    -m32:生成32位的指令格式
    

    3. 分析

    初始状态:从main开始执行

    • 假设起始地址为2016,%ebp、%esp都指向2016。

    第18行:pushl %ebp

    • 相当于先执行 subl $4,%esp => esp指向2012;
    • 然后 movl %ebp,(%esp) => 将ebp的值放在esp所指向位置,即把“2016”放在2012的位置上。
    • ebp = 2016,esp = 2012

    第19行:movl %esp,%ebp

    • ebp指向与esp相同的位置2012上。
    • ebp = 2012,esp = 2012

    第20行:subl $4,%esp

    • esp减4,即向下移动到位置2008上。
    • ebp = 2012,esp = 2008

    第21行:movl $2,(%esp)

    • 把立即数2放在esp所在位置2008上。
    • ebp = 2012,esp = 2008

    第22行:call fun

    • 调用函数fun
    • push %eip => esp向下移到位置2004,把eip(下一条指令所在,即第23行)放在该位置上,然后将fun函数所在赋给eip,执行fun函数的指令。
    • ebp = 2012,esp = 2004

    第8行:跳转到fun的初始状态

    • ebp = 2012,esp = 2004

    第9行:push %ebp

    • ebp = 2012,esp = 2000

    第10行:movl %esp,%ebp

    • ebp = 2000,esp = 2000

    第11行:subl $4,%esp

    • ebp = 2000,esp = 1996

    第12行:movl 8(%ebp),%eax

    第13行:movl %eax,(%esp)

    • 将(ebp+8)即位置2008存放的值通过eax放在esp位置1996上
    • eax = 2
    • ebp = 2000,esp = 1996

    第14行:call add

    • ebp = 2000,esp = 1992

    第1行:跳转到add的初始状态

    • ebp = 2000,esp = 1992

    第2行:pushl %ebp

    • ebp = 2000,esp = 1988

    第3行:movl %esp,%ebp

    • ebp = 1988,esp = 1988

    第4行:movl 8(%ebp),%eax

    第5行:addl $7,%eax

    • 将(ebp+8)即位置1996处存放的值赋给eax;
    • 此时,eax = 2,然后加7,eax = 9。
    • ebp = 1988,esp = 1988

    第6行:popl %ebp

    • 相当于先movl (%esp),%ebp => 把esp位置1988存放的值赋给ebp,ebp指向2000。
    • 然后addl $4,%esp => 将esp上移到位置1992。
    • ebp = 2000,esp = 1992

    第7行:ret

    • 相当于popl %eip
    • esp上移到位置1996,指令执行第15行。
    • ebp = 2000,esp = 1996

    第15行:leave

    • 相当于先movl %ebp,%esp => 将esp指向ebp,即位置2000。
    • 然后popl %ebp => ebp指向位置2000存储的值,即位置2012处,esp指向位置2004。
    • ebp = 2012,esp = 2004

    第16行:ret

    • ebp = 2012,esp = 2008

    第23行:addl $3,%eax

    • eax加3,eax = 12
    • ebp = 2012,esp = 2008

    第24行:leave

    • ebp = 2016,esp = 2016

    第25行:ret

    • 回到执行main之前的位置

    寄存器内容变化

    三、总结:关于计算机是如何工作的

    1. 复杂又简单的计算机:计算机能实现许多看起来很复杂的功能,计算和处理大量的数据,但是,它实现这些复杂功能是不断地重复大量既定的简单的操作。
    2. 程序:我们一般做的,是告诉计算机操作的步骤、输入的数据是什么、处理后的结果如何存储。然后,计算机会尽可能忠实地按照程序的顺序将每一个操作步骤的指令取出,变成机器语言,通过软硬件协同工作。
    3. 汇编语言:汇编语言其实也是机器语言的一种翻译。现在编译器功能优化的比较强大,学习汇编语言真正用的时候并不多,但它是我们分析处理问题的一种角度。能够看懂汇编语句,在分析程序真正执行的流程、单步调试程序的方面都是有帮助的。
  • 相关阅读:
    #Laravel笔记# 使用SMTP发送邮件功能
    #Laravel笔记# 监听事件
    idea 常见问题
    python常见函数汇总
    双DNN排序模型:在线知识蒸馏在爱奇艺推荐的实践
    机器学习算法GBDT
    Hive表数据同步到es
    目标检测资料
    zeppelin的介绍与使用
    Java汉字获取拼音、笔划、偏旁部首
  • 原文地址:https://www.cnblogs.com/hyq20135317/p/5217912.html
Copyright © 2011-2022 走看看