本节书摘来自异步社区《操作系统真象还原》一书中的第0章,第0.24节,作者:郑钢著,更多章节内容可以访问云栖社区“异步社区”公众号查看
0.24 如何控制CPU的下一条指令
其实此问题我一直犹豫要不要写出来,因为大部人都觉得这个问题有些匪夷所思,CPU是负责执行指令的,它会按照程序的执行流程走,此问题的目的其实就是想知道如何牵着CPU的鼻子走。当初我被问这个问题时也觉得很诧异,甚至我觉得自己可能没理解人家的意思。后来他这样跟我说:“CPU要执行的下一条指令是在CS:IP寄存器吧?”我说:“是啊”。他又问:“CS和IP寄存器,是用mov指令修改的吗?”我听后,顿时觉得他这个问题很有意义,暗自对他有些小敬佩,我相信很多人都没想过,CS和IP能不能用mov指令去修改。
是这样的,我们常说的用于存放下一条指令地址的寄存器称为程序计数器PC(Program Counter)。这个名词在我看来是个概念级别的内容,它只是CPU中有关下一条指令存放地址的统称,也就是说PC是用来表示下一条指令的存放地址,具体的实现形式不限,后面会有所讨论。
CPU按照指令集可以分为很多种,由于PC只是个概念,所以在不同种类的CPU中,有不同的实现。注意啦,这里的“不同种类”不是指CPU品牌,而是指CPU体系结构,如INTEL和AMD同属x86构架,如果您对此不了解,细心的我早已在下面为您准备好了体系结构、指令集的相关内容。由于此方面内容较独立,我专门将其组织成一个小节供大伙儿参考,如果您现在感兴趣,可以先参阅“指令集、体系结构、微架构、编程语言”这一节。
在x86体系结构的CPU中,也就是咱们大多数人使用的INTEL或AMD公司出品的桌面处理器,程序计数器PC并不是单一的某种寄存器,它是一种寄存器组合,指的段寄存器CS和指令指令寄存器IP。
CS和IP是CPU待执行的下一条指令的段基址和段内偏移地址,不能直接用mov指令去改变它们,我想可能的一个原因是:mov指令一次只能改变一个寄存器,不能同时将cs和ip都改变。如果只改变了其中一个会引起错误。如改变了cs的值后,ip的值还是原先cs段的偏移,很难保证新的cs段内的偏移地址ip处的指令是正确的。因此,有专门改变执行流的指令,如jmp、call、int、ret,这些指令可以同时修改cs和ip,它们在硬件级别上实现了原子操作。
以上说的是x86体系的CPU,其他类型的CPU是怎样的呢?这就取决于具体实现啦,咱们这里拿ARM举例,它的程序计数器有个专门的寄存器,名字就叫PC,想要改变程序流程,直接对该寄存器赋值便可。
与x86不同的是在ARM中可以用mov指令来修改程序流,在ARM体系CPU的汇编器中,寄存器的名称在汇编语言中是以“r数字”的形式命名的,例如汇编代码:mov pc,r0,表示将寄存器r0中的内容赋值给程序寄存器PC,这样就直接改变了程序的执行流。
总结一下,程序计数器PC负责处理器的执行方向,它只是获取下一条指令的方法形式,在不同体系结构的CPU中有不同的实现方法。