CPU|关于CPU的12个硬核干货!( 二 )


汇编语言和机器语言一一对应 , 这点和高级语言不同 , 我们通常把汇编语言编写的程序转换为机器语言的这个过程 , 称之为汇编 。 与之相反 , 将机器语言转化为汇编语言的过程称之为反汇编 。
汇编语言可以帮助你理解计算机做了什么工作 , 机器语言级别的程序通过寄存器来处理 , 上面代码中的eaxebp都是表示的寄存器 , 它们是CPU内部寄存器的名称 。 因此可以说 , CPU是一系列寄存器的集合体 。
一般在内存中的存储通过地址编号来表示 , 寄存器的种类是通过名字来区分 。 那些不同类型的CPU , 其内部寄存器的种类、数量以及寄存器存储的数值范围也都是不同的 。 不过 , 根据功能的不同 , 我们可以将寄存器划分为下面几类:

其中 , 程序计数器、标志寄存器、累加寄存器、指令寄存器和栈寄存器只有一个 , 其他寄存器一般有好几个 。
07程序计数器
程序计数器是用来存储下一条指令所在单元的地址 。 程序在执行时 , PC的初值作为程序第一条指令的地址 , 在顺序执行程序时 , 控制器先按照程序计数器所指出的指令地址 , 从内存中取出一条指令 , 随后分析和执行该指令 , 并同时将PC的值加1指向下一条要执行的指令 。
我们可以通过一个事例来仔细看一下程序计数器的执行过程:

这是一段进行相加的操作 , 程序启动 , 在经过编译解析后 , 会经由操作系统把硬盘中的程序复制到内存中 。
以上示例程序 , 就是将123和456执行相加的操作 , 随后将结果输出到显示器上 , 因为使用机器语言很难描述 , 所以这些都是经过翻译后的结果 。
事实上 , 每个指令和数据都有可能分布在不同的地址上 , 但是为了更好的说明 , 就把组成一条指令的内存和数据放在了一个内存地址上 。
地址0100是程序运行的起始位置 , Windows等操作系统把程序从硬盘复制到内存以后 , 就会将程序计数器作为设定为起始位置0100 , 然后再执行程序 , 每次执行一条指令后 , 程序计数器的数值就会增加1 , 或者是直接指向下一条指令的地址 。
随后 , CPU会根据程序计数器的数值 , 从内存中读取命令并且执行 , 换言之 , 程序计数器控制着程序的流程 。
08条件分支和循环机制
小伙伴们都学过高级语言 , 高级语言汇总的条件控制流程主要分为顺序执行、条件分支、循环判断三种 。
●顺序执行是按照地址的内容顺序的执行命令 。
●条件分支是根据条件执行任意地址的指令 。
●循环是重复执行同一地址的指令 。
一般情况下 , 顺序执行的情况较简单 , 每次执行一条指令程序计数器的值就是+1 。 条件和循环分支会使得程序计数器的值指向任意的地址 , 这样一来 , 程序就可以返回到上一个地址来重复执行同一个指令 , 或者跳转到其它任意指令 。
下面 , 我们就以条件分支举例来说明程序的执行过程:

程序的开始过程和顺序流程是一样的 , 程序的顺序流程和开始过程相同 。 CPU从0100处就开始执行命令 , 在0100和0101中都是顺序执行 , PC的值顺序+1 , 执行到0102地址的指令时 , 判断0106寄存器的数值大于0 , 跳转到0104地址的指令 , 再将数值输到显示器中 , 随后结束程序 , 0103的指令就被跳过了 。 这和我们程序中的if()判断相同 , 在不满足条件的情况下 , 指令一般会直接跳过 。 因此 , PC的执行过程没有直接+1 , 而是下一条指令的地址 。
09标志寄存器
条件和循环分支会使用到 jump(跳转指令) , 会根据当前的指令来判断是否跳转 , 上面我们提到了标志寄存器 , 无论当前累加寄存器的运算结果是正数、负数还是零 , 标志寄存器都会将其保存 。 CPU在进行运算时 , 标志寄存器的数值会根据当前运算的结果自动设定 , 运算结果的正、负和零三种状态由标志寄存器的三个位表示 。 标志寄存器的第一个字节位、第二个字节位、第三个字节位各自的结果都为1时 , 分别代表着正数、零和负数 。

CPU的执行机制比较有意思 , 假设累加寄存器中存储的XXX和通用寄存器中存储的YYY做比较 , 执行比较的背后 , CPU的运算机制就会做减法运算 。 而无论减法运算的结果是正数、零还是负数 , 都会保存到标志寄存器中 。 结果为正表示XXX比YYY大 , 结果为零表示XXX和YYY相等 , 结果为负表示XXX比YYY小 , 程序比较的指令 , 实际上是在CPU内部做减法运算 。
10函数调用机制