1.2 CPU是寄存器的集合体
前面介绍的CPU的四个组成部件中,需要程序员特别关注的只有寄存器,其余三个部件不需要关注。为什么我们必须关注寄存器呢?这是因为寄存器是程序的描述对象。
请看代码清单1-1,这是用汇编语言编写的程序的部分内容。机器语言指令的本质是电子信号,我们用英语单词或其缩写(称为助记符)表示每一种信号的功能,就构成了汇编语言。例如,mov和add分别代表传送(move)数据和加法运算(addition)操作。汇编语言和机器语言基本上是一一对应的,这一点和C语言、Java等高级编程语言有很大差别,因此要讲解CPU的工作原理,用汇编语言是最合适的。将汇编语言程序转换成机器语言的过程称为汇编(assemble),反过来,将机器语言程序转换成汇编语言的过程称为反汇编(disassemble)。希望大家能够记住这两个名词。
代码清单1-1 汇编语言程序示例(其中带颜色的地方表示寄存器)
movl -4(%ebp), %eax … 将内存中的值读入 eax
addl -8(%ebp), %eax … 将内存中的值累加到 eax
movl %eax, -12(%ebp) … 将 eax的值(加法运算结果)存放到内存中
通过阅读汇编语言程序,我们就能理解机器语言程序的工作原理。之所以给大家展示代码清单1-1中的汇编语言程序,是想告诉大家,在机器语言层面上,程序的操作都是使用寄存器来完成的。也就是说,从程序员的视角来看,CPU就是寄存器的集合体。至于控制器、运算器和时钟,我们只要知道它们的存在就足够了。
在代码清单1-1中,eax和ebp都表示寄存器,大家应该能大致看出,这段程序是在使用寄存器来存放数据和进行加法运算。这段程序所使用的是32位x86架构CPU的汇编语言,其中,eax和ebp都是CPU内部的寄存器的名称。内存中存储数据的位置是用地址来区分的,寄存器则是用名称来区分的。
这些内容听起来有点难,但是请大家放心,我们并不需要记住某种CPU中所有寄存器的名称,也不需要掌握汇编语言,重要的是对CPU怎样处理程序有一个大概的印象。也就是说,大家用高级编程语言编写的程序,最终都会被编译成机器语言,然后在CPU内部通过寄存器进行处理。例如,aa=1+2这样的高级编程语言程序,在转换成机器语言之后就是用寄存器来进行存储处理和加法运算操作的,这一点大家需要知道。
CPU的类型不同,其内部的寄存器数量、类型及寄存器中能存储的数据长度也有所不同,但如果按照功能进行大致分类,就是表1-1这样。寄存器中存放的值可以是指令,也可以是数据,其中数据又分为“用于运算的数值”和“表示内存地址的数值”。不同类型的值会存放在不同类型的寄存器中。CPU中的每个寄存器都有不同的功能,例如用于运算的值存放在累加器中,表示内存地址的值存放在基址寄存器和变址寄存器中。代码清单1-1中出现的eax是累加器,ebp是基址寄存器。
表1-1 寄存器的主要类型及其功能
对程序员来说,CPU就像图1-3展示的那样,是由具有不同功能的寄存器所构成的集合体。一般来说,程序计数器、累加器、标志寄存器、指令寄存器、栈寄存器各仅有一个,其他类型的寄存器可以有多个。其中,程序计数器和标志寄存器属于比较特殊的寄存器,这一点会在后面的章节中详细介绍。图1-3中省略了程序员不需要关注的寄存器(如存放指令的指令寄存器等)。
图1-3 从程序员的视角看CPU(CPU是寄存器的集合体)