• 《汇编语言第三版(王爽)》 读书笔记


    前言


      

      说起自己读汇编,总有人会在问:读汇编有啥意义?读汇编对我的开发工作有帮助吗?...我觉得读汇编是为了让我们更好地有计算机工作原理方面的知识,不仅仅是一味地高屋建瓴。就拿 IDE 和 Linux gcc 来说,我们为什么要试着用 gcc 去编译链接并生成可执行程序,而不是点一下 Run 程序就能跑起来?原因还是在我们想探究程序运行的本质。

      而汇编就是一门帮助我们更好地理解程序如何“跑起来”的语言,它最接近机器语言这门计算机唯一能识别的语言,深入数据在内存单元的存储,直接对内存单元进行操作,自然就涉及到 CPU 相关的运作等等等计算机核心部件,相信读了它,我们对操作系统能有更深入地认识。

    CPU与数据


      由于最终运行程序的是CPU,所以我们使用汇编语言编程的时候,最好从CPU的角度去考虑问题,这里谈谈存储器、三条总线、内存地址空间的概念。

    • 存储器
      • 想让CPU工作,就得给CPU提供指令和数据,而这些东西存在哪呢?存在内存器里,也就是我们常说的内存,这些内存被划分成多个存储单元,顺序编号,以方便CPU从里头拿出、放入数据。
    • 三条总线
      • 三条总线的目的是让CPU知道此时是该从哪儿拿出放入数据,而想要完成这一步操作,就得告诉CPU:在哪儿、干什么。
      • 地址总线:将地址传输给CPU,告诉CPU在哪儿操作
      • 控制总线:告诉CPU是读出数据还是写入数据
      • 数据总线:传输数据
    • 内存地址空间
      • 什么叫内存地址空间?由于我们的地址总线数量是一定的,那代表了我们可得到的地址数值也是有限的,举个例子:地址总线数量为10,那么从编号为0到1024的内存单元可以被寻址到,而在往后的地址就无可奈何了。这1024个可被寻址的内存单元就构成了内存地址空间。
      • 内存地址空间是一个逻辑存储器,因为它把不同的硬件内存都映射在一个空间里,占有不同的地址段,而在实际上硬件的内存位置是离散的。
      • 我们在对内存地址空间进行操作的同时,实际上就是对相对应的物理存储器进行操作。

    寄存器


      寄存器是我们唯一能用指令读写的部件,它用来暂时存储数据、指令、地址,比内存存储要快、方便。规定它的名字即是它的地址。0806中寄存器有如下几种:

    • 数据寄存器,用于存储数据,如AX(累加),BX(基址,可用于间接寻址,如[bx]),CX(技术),DX(暂存数据)
    • 段地址寄存器,用于存储段地址,如CS(代码段),DS(数据段),SS(堆栈段)
    • 指针寄存器,如IP(告诉CPU当前单元读取的是指令)、SP(当前指向的是栈顶)、BP(当前指向的是栈底)
    • 标志寄存器,通过标志确定对应事件是否发生,如CF(中断是否发生)

      写汇编程序我们需要知道数据存在哪、长度是多少,要对其进行怎样的操作,而这些步骤都要通过寄存器才能实现。

    物理地址


      编号后的内存地址空间中每一个内存单元都有唯一的地址,我们把这个唯一的地址称为物理地址。然而,8086是16位CPU,也就是说内部只能一次性处理、传输的信息是16位的,但是物理地址地址往往比16位数据要大,这该怎么办?

      操作系统对16的CPU给出了计算物理地址的办法:段地址×16+偏移地址=物理地址

      这是个很机智的做法,先确定一个起点,然后再以起点开始算它与目的地之间的距离,这么做的好处是只要你定一个规则,比如说:起点×10+偏移距离=目的地,就可以保证起点的位数也是足够小的。由于CPU中地址加法器可以处理进位,所以CPU可以一次性处理起点×10的数据。

    段与段寄存器


      

      段的概念来自于CPU中计算物理地址的公式:段地址×16+偏移地址=物理地址,实际上内存是一个个连续的内存单元,并不会分段。作为程序员,我们可以根据自身需要将一组内存定义为一个段。

      两个点需要注意:

        1.由于计算物理地址公式,段的地址肯定是16的倍数

        2.偏移地址是16位,所以一个段的长度最大为 64KB

      可能在之前的学习中,我们耳熟能详地就是代码段、数据段与栈段了,但是只知道代码段是存对应的代码、数据段是存数据、栈段用于存储程序中的局部变量,但是又想在内存中存储的是机器码,莫非对应每个机器码都要标记它是不是要执行代码、数据不成?

      对于这个问题,读完汇编后才明白,我们可以将代码数据存放在代码段里,然后通过 CS:IP 指向某内存单元,该内存单元的数据将被当成指令读取并送入指令缓冲器,IP指向下一条指令,最后将缓冲器中的指令执行,如此循环,一个程序就跑起来了。

      数据也是同理,用“DS:偏移地址 ”表示该单元存储的是数据。从这个角度上看,其实数据与程序本身的存储是没有区别的,判断是否是指令依靠的是IP,IP指向哪哪儿就成了指令。

      由于我们需要数据的动态分配,所以引入了栈段,在编写程序时,往往数据段存储全局变量,而栈段存储局部变量。我们通过 ss 表示栈段,ss:sp 指向栈顶单元,ss:bp 表示单元。你可能会有疑问,我们可以通过 ss:0000 就知道栈的底部单元的物理地址了,为什么还需要bp?我的理解是利用 bp sp 可以动态模拟当前函数的内存,当函数返回上一层时,bp sp 又再次变化,指向当前函数的内存。

      

       

    ————全心全意投入,拒绝画地为牢
  • 相关阅读:
    使用comet架构实现了一个基于网页的视频监控prototype!!!!哇哈哈庆祝一下
    Pixysoft.Framework.Noebe.Datamining 数据挖掘开发实录
    论创业成功!让大家的青春充满着无限美好的回忆
    新年第一篇 数据库备份恢复系统上线的挫折
    .Net FrameWork 4.0中使用EF向数据库插入数据报datatime2类型错误的解决办法
    RoRoWoBlog 开源博客系统介绍
    第一次偶然出现的“System.Data.Entity.dll”类型的异常
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    我也来说说Entity Frame Work 4中的数据库优先和代码优先两种方式(2)
    Asp.net MVC 2 + Castle + NHibernate 项目实战(1)
  • 原文地址:https://www.cnblogs.com/Bw98blogs/p/8227784.html
Copyright © 2020-2023  润新知