2.10 CS和IP(1)
CS和IP是中两个最关键的寄存器,它们指示了CPU当前要读取指令的地址 。CS为代码段寄存器,IP为指令指针寄存器,从名称上我们可以看出它们和指令的关系 。
在机中 , 任意时刻,设CS中的内容为M,IP中的内容为N,将从内存M 16+N单元开始,读取一条指令并执行 。
也可以这样表述:8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行 。
图2.10展示了读取、执行指令的工作原理(图中只包括了和所要说明的问题密切相关的部件,图中数字都为十六进制) 。
文章插图
图2.10 读取和执行指令的相关部件
图2.10说明如下 。
(1)当前状态:CS中的内容为2000H , IP中的内容为0000H;
(2)内存~单元存放着可执行的机器码;
(3)内存~单元中存放的机器码对应的汇编指令如下 。
地址:~ , 内容:B8 23 01,长度:3Byte , 对应汇编指令:mov ax,0123H
地址:~,内容:BB 03 00,长度:3Byte,对应汇编指令:mov bx,0003H
地址:~,内容:89 D8,长度:2Byte,对应汇编指令:mov ax,bx
地址:~,内容:01 D8 , 长度:2Byte,对应汇编指令:add ax,bx
下面的一组图(图2.11~图2.19),以图2.10描述的情况为初始状态,展示了读取、执行一条指令的过程 。注意每幅图中发生的变化(下面对的描述,是在逻辑结构、宏观过程的层面上进行的,目的是使读者对CPU工作原理有一个清晰、直观的认识,为汇编语言的学习打下基础 。其中隐蔽了CPU的物理结构以及具体的工作细节) 。
文章插图
图2.11 初始状态(CS:2000H , IP:0000H,CPU将从
内存2000H×16+0000H处读取指令执行)
文章插图
图2.12 CS、IP中的内容送入地址加法器(地址加法
器完成:物理地址=段地址×16+偏移地址)
文章插图
图2.13 地址加法器将物理地址送入输入输出控制电路
文章插图
图2.14 输入输出控制电路将物理地址送上地址总线
文章插图
图2.15 从内存单元开始存放的
机器指令B8 23 01通过数据总线被送入CPU
文章插图
图2.16 输入输出控制电路将机器指令B8 23 01送入指令缓冲器
文章插图
图2.17 IP中的值自动增加
(读取一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令 。因当前读入的指令
长度为3个字节,所以IP中的值加3 。此时,CS:IP指向内存单元2000:0003 。)
2.10 CS和IP(2)
文章插图
图2.18 执行控制器执行指令B8 23 01(即mov ax,0123H)
文章插图
图2.19 指令B8 23 01被执行后AX中的内容为0123H
(此时,CPU将从内存单元2000:0003处读取指令 。)
下面的一组图(图2.20~图2.26),以图2.19的情况为初始状态,展示了继续读取、执行3条指令的过程 。注意IP的变化(下面的描述中,隐蔽了读取每条指令的细节) 。
文章插图
图2.20 CS:2000H , IP:0003H(CPU将从内存2000H×16+0003H处读取指令BB 03 00)
文章插图
图2.21 CPU从内存处读取指令BB 03 00入指令缓冲器(IP中的值加3)
文章插图
图2.22 执行指令BB 03 00(即mov bx,0003H)
文章插图
图2.23 CPU从内存处读取指令89 D8入指令缓冲器(IP中的值加2)
文章插图
图2.24 执行指令89 D8(即mov ax,bx)后,AX中的内容为0003H
文章插图
图2.25 CPU从内存处读取指令01 D8入指令缓冲器(IP中的值加2)
文章插图
图2.26 执行指令01 D8(即add ax,bx)后,AX中的内容为0006H
通过上面的过程展示,的工作过程可以简要描述如下 。
(1)从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
(2)IP=IP+所读取指令的长度 , 从而指向下一条指令;
(3)执行指令 。转到步骤(1),重复这个过程 。
在加电启动或复位后(即CPU刚开始工作时)CS和IP被设置为CS=FFFFH,IP=0000H,即在机刚启动时,CPU从内存单元中读取指令执行,单元中的指令是机开机后执行的第一条指令 。
现在 , 我们更清楚了CS和IP的重要性,它们的内容提供了CPU要执行指令的地址 。
我们在第1章中讲过,在内存中 , 指令和数据没有任何区别,都是二进制信息,CPU在工作的时候把有的信息看作指令,有的信息看作数据 。现在,如果提出一个问题:CPU根据什么将内存中的信息看作指令?如何回答?我们可以说,CPU将CS:IP指向的内存单元中的内容看作指令,因为,在任何时候,CPU将CS、IP中的内容当作指令的段地址和偏移地址,用它们合成指令的物理地址,到内存中读取指令码 , 执行 。如果说,内存中的一段信息曾被CPU执行过的话,那么 , 它所在的内存单元必然被CS:IP指向过 。
2.11 修改CS、IP的指令
在CPU中,程序员能够用指令读写的部件只有寄存器,程序员可以通过改变寄存器中的内容实现对CPU的控制 。CPU从何处执行指令是由CS、IP中的内容决定的 , 程序员可以通过改变CS、IP中的内容来控制CPU执行目标指令 。
我们如何改变CS、IP的值呢?显然 , 必须提供相应的指令 。我们如何修改AX中的值?可以用mov指令,如mov ax,123将ax中的值设为123 , 显然 , 我们也可以用同样的方法设置其他寄存器的值,如mov bx,123,mov cx,123,mov dx,123等 。其实,大部分寄存器的值,都可以用mov指令来改变,mov指令被称为传送指令 。
但是 , mov指令不能用于设置CS、IP的值,原因很简单,因为没有提供这样的功能 。为CS、IP提供了另外的指令来改变它们的值 。能够改变CS、IP的内容的指令被统称为转移指令(我们以后会深入研究) 。我们现在介绍一个最简单的可以修改CS、IP的指令:jmp指令 。
若想同时修改CS、IP的内容,可用形如"jmp段地址:偏移地址"的指令完成,如
jmp 2AE3:3,执行后:CS=2AE3H,IP=0003H , CPU将从处读取指令 。
jmp 3:0B16,执行后:CS=0003H,IP=0B16H,CPU将从处读取指令 。
文章插图
"jmp 段地址:偏移地址"指令的功能为:用指令中给出的段地址修改CS,偏移地址修改IP 。
若想仅修改IP的内容,可用形如"jmp 某一合法寄存器"的指令完成,如
jmp ax,指令执行前:ax=1000H,CS=2000H,IP=0003H指令执行后:ax=1000H,CS=2000H,IP=1000Hjmp bx,指令执行前:bx=0B16H,CS=2000H,IP=0003H指令执行后:bx=0B16H,CS=2000H,IP=0B16H
"jmp 某一合法寄存器"指令的功能为:用寄存器中的值修改IP 。
jmp ax , 在含义上好似:mov IP,ax 。
注意,我们在适当的时候,会用已知的汇编指令的语法来描述新学的汇编指令的功能 。采用一种"用汇编解释汇编"的方法来使读者更好地理解汇编指令的功能 , 这样做有助于读者进行知识的相互融会 。要强调的是,我们是用"已知的汇编指令的语法"进行描述,并不是用"已知的汇编指令"来描述 , 比如,我们用mov IP,ax来描述jmp ax , 并不是说真有mov IP,ax这样的指令,而是用mov指令的语法来说明jmp指令的功能 。我们可以用同样的方法描述jmp 3:01B6的功能:jmp 3:01B6 在含义上好似mov CS,3 mov IP,01B6 。
内存中存放的机器码和对应的汇编指令情况如图2.27所示,设CPU初始状态:CS=2000H,IP=0000H,请写出指令执行序列 。思考后看分析 。
文章插图
图2.27 内存中存放的机器码和对应的汇编指令
分析:
CPU对图2.27中的指令的执行过程如下 。
(1)当前CS=2000H,IP=0000H,则CPU从内存2000H×16+0=处读取指令,读入的指令是:B8 22 66(mov ax,6622H),读入后IP=IP+3=0003H;
(2)指令执行后 , CS=2000H,IP=0003H,则CPU从内存2000H×16+0003H =处读取指令,读入的指令是:EA 03 00 00 10(jmp 1000:0003),读入后IP=IP+5=0008H;
(3)指令执行后,CS=1000H,IP=0003H,则CPU从内存1000H×16+0003H =处读取指令,读入的指令是:B8 00 00(mov ax,0000),读入后IP=IP+3=0006H;
(4)指令执行后,CS=1000H,IP=0006H,则CPU从内存1000H×16+0006H =处读取指令,读入的指令是:8B D8(mov bx,ax),读入后IP=IP+2=0008H;
(5)指令执行后 , CS=1000H,IP=0008H,则CPU从内存1000H×16+0008H =处读取指令,读入的指令是:FF E3(jmp bx),读入后IP=IP+2=000AH;
(6)指令执行后,CS=1000H,IP=0000H , CPU从内存处读取指令……
经分析后,可知指令执行序列为:
(1)mov ax,6622H
(2)jmp 1000:3
(3)mov ax,0000
(4)mov bx,ax
(5)jmp bx
(6)mov ax,0123H
(7)转到第3步执行
2.12 代码段(1)
前面讲过 , 对于机,在编程时 , 可以根据需要,将一组内存单元定义为一个段 。我们可以将长度为N(N≤64KB)的一组代码,存在一组地址连续、起始地址为16的倍数的内存单元中,我们可以认为,这段内存是用来存放代码的,从而定义了一个代码段 。比如,将:
mov ax,0000(B8 00 00)add ax,0123(05 23 01)mov bx,ax(8B D8)jmp bx(FF E3)
这段长度为10个字节的指令,存放在~的一组内存单元中,我们就可以认为,~这段内存是用来存放代码的 , 是一个代码段,它的段地址为123BH , 长度为10个字节 。
如何使得代码段中的指令被执行呢?将一段内存当作代码段,仅仅是我们在编程时的一种安排,CPU并不会由于这种安排,就自动地将我们定义的代码段中的指令当作指令来执行 。CPU只认被CS:IP指向的内存单元中的内容为指令 。所以,要让CPU执行我们放在代码段中的指令,必须要将CS:IP指向所定义的代码段中的第一条指令的首地址 。对于上面的例子,我们将一段代码存放在~内存单元中,将其定义为代码段 , 如果要让这段代码得到执行,可设CS=123BH、IP=0000H 。
2.9~2.12 小结
(1) 段地址在的段寄存器中存放 。当要访问内存时,由段寄存器提供内存单元的段地址 。有4个段寄存器,其中CS用来存放指令的段地址 。
(2) CS存放指令的段地址 , IP存放指令的偏移地址 。
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行 。
(3) 的工作过程:
【汇编语言--x86 CS IP】① 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;