汇编语言(2)——寻址与执行

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidthephantomthiefI/article/details/77172772

《汇编语言(王爽 著)》读书笔记

1. 8086CPU形成物理地址的方式

1.1 段的概念及使用

  8086CPU共有20根地址总线,理论上其寻址能力最大寻址空间为220即1MB。然而8086CPU为16位CPU,也就是说它能一次行处理、传输和暂存的为16位。它采用一种在CPU内部用两个16位地址合成的方法来形成一个20位的物理地址,如图2.1所示。


8086CPU形成物理地址的方式


图2.1 8086CPU形成物理地址的方式

  8086CPU中的相关部件给出两个16位的地址,一个被称为段地址(Segment Address,简称SA),一个被称为偏移地址(Effective Address,简称EA)。地址加法器采用

物理地址 = 段地址 * 16 + 偏移地址

的方法合成物理地址。其本质就是,CPU用一个基础地址加上一个相对于基础地址的偏移地址,得到一个内存单元的物理地址。不难看出,段地址是16字节对齐的,并且一个段的大小最大可以为216即64KB。

  但是这并不意味着内存已经被事先划分为16字节为一个单位的段,段的划分和解释只来自于CPU。比如,我们可以认为物理地址为10000H~100FFH的内存单元组成一个段。该段的起始地址(基础地址)为10000H,段地址为1000H,大小为100H。也可以认为物理地址为10010H~100FFH的内存单元组成一个段。该段的起始地址为10000H,段地址为1001H,大小为EFH。通常我们将物理地址记作

段地址:偏移地址

的形式。这样,对于同一个物理地址100FFH,我们既可以用1000H:FFH来表示,也可以用1001H:EFH来表示。可见段只是一种概念上的划分,基础地址和偏移地址相加才是其本质。

1.2 段寄存器

  上面提到,“8086CPU中的相关部件给出两个16位的地址”,这里给出段地址的相关部件,其实就是段寄存器,也就是CS,DS,SS和ES其中之一。而给出偏移地址的方式可以有多种,但只能是是特定寄存器中的数据或者立即数或者它们的加和。关于偏移地址的给出就涉及到了寻址的问题,我们先讨论一下几个段寄存器。

1. 代码段寄存器CS(Code Segment)
存储指令所在内存单元的段地址,在CPU到内存中取指令时,段地址默认从中获取。
2. 数据段寄存器DS(Data Segment)
存储数据所在内存单元的段地址,在指令操作数寻址的过程中,段地址默认从中获取。
3. 堆栈段寄存器SS(Stack Segment)
存储栈段所在内存单元的段地址,在push和pop操作时,访问内存单元的段地址从中获取。
4. 附加段寄存器ES(Extra Segment)
可以在指令操作数寻址时替换默认的DS寄存器,以使用新的段地址。

  这四个段寄存器都可以用在指令操作数寻址中。在8086CPU的汇编指令中,操作数的偏移地址会用中括号括起来,前面可以选择性地加上段寄存器。如,用[bx]表示偏移地址为寄存器bx中的数值,用es:[bx]表示段地址为寄存器es中的数值,而偏移地址为寄存器bx中的数值。结合前面关于段寄存器的讨论,在指令mov ax,[bx]中,第二个操作数的物理地址默认为DS:BX,而如果使用mov ax,es:[bx],其物理地址就变为了ES:BX。当然这里的ES也可以换成DS,CS和SS。

  特殊地,当CS用来确定下一条指令的物理地址时,其偏移地址一定从指令指针寄存器IP中获取;当SS寄存器用在push和pop指令中来确定栈顶的物理地址时,其偏移地址只能从堆栈指针寄存器SP中获取。

  还有一点值得注意的,在用mov指令给段寄存器赋值时,一定要经过一个通用寄存器中转,类似mov ds,0b40h的汇编指令是不合法的。正确的应为先mov ax,0b40h然后mov ds,ax。这属于8086CPU硬件设计的问题,了解就好。

2. 指令的读取与执行

  相关的结构如图2.2所示。


8086PC读取指令和执行的相关部件


图2.2 8086PC读取指令和执行的相关部件

  8086PC的指令的读取和执行过程如下,具体过程如图2.3所示。

CS和IP的内容被送入地址加法器
地址加法器将物理地址送入输入输出控制电路
输入输出控制电路将物理地址送上地址线
从指定位置开始存放的机器指令通过地址线被送入CPU
输入输出控制电路将机器指令送入指令缓冲寄存器
IP中的值自动增加从而指向下一条指令
执行控制器执行指令
再次重复以上步骤


8086PC读取指令和执行的过程(1)
8086PC读取指令和执行的过程(2)


图2.3 8086PC读取指令和执行的过程

  可见CS:IP所表示的物理地址就是指令的地址,所以CS寄存器被称为代码段寄存器。
  另有一点值得注意的是,程序刚载入内存时,寄存器CX的值为程序的返回时的偏移地址

3. 8086CPU的寻址方式

  大多数机器指令,都由两部分构成——操作符(operator)和操作数(operand)。那些不含操作数的指令,实际上是默认了操作数的位置。汇编指令与机器指令是一一对应的,因而也是如此。对于特定的CPU,机器指令的长度是有限的,指令的操作类型即操作符也是给定的有限种,但是操作数的大小是不固定的。为了使操作数长度不受指令长度的限制,我们把操作数放在“各种位置”并且使用各种寻址方式(addressing mode)来确定操作数的值。所谓的寻址(addressing),全称应该是操作数寻址,最终目的不是为了找到某个地址而是为了确定操作数的值。在8086CPU中,对于涉及到内存的寻址方式,虽然可以指定使用不同的段地址,但我们主要关注的是通过各种方式产生的偏移地址,也被称为有效地址(effective address)。一般用记号(ax)(X)分别表示内存中物理地址为寄存器ax的值和物理地址为X的内存单元的内容,用SA表示段地址,EA表示偏移地址。8086CPU的各种寻址方式如表2.1所示。


8086CPU的寻址方式

表2.1 8086CPU的寻址方式

  这里的相对寻址需要说明一下,在汇编指令中,短转移指令jmp short和近转移指令jmp near后面的操作数是汇编代码中的“标号”,这些“标号”实际上是地址。而当编译形成机器指令后,这些“标号”被翻译成了相对地址,即目的地址的IP值和jmp指令的地址的IP值的差。也就是说,只有从机器指令来看,才能发现它们使用的是相对寻址来获取操作数。它们都是段内转移指令,只改变IP寄存器的值。CS和IP寄存器的值也只能通过类似的转移指令来改变,而不能像其他寄存器(除了PSW寄存器)那样,使用mov指令。

  从表中可以看出,在8086CPU的汇编指令中,用中括号将偏移地址括起来表示在内存单元中进行寻址。而且,关于中括号中的内容,是有要求的:

只有bx,bp。si,di这四个寄存器可以用在[...]中进行内存单元寻址;
这四个寄存器可以单个出现。或者只能以四种组合出现bx和si,bx和di,bp和si,bp和di,当然这些情况下都可以再加数字;
若在[...]中使用了bp寄存器,没有指明段寄存器时,默认的段寄存器为SS,若未使用bp,默认的段寄存器为DS

  可见DS为内存单元寻址的默认寄存器,因此被称为数据段寄存器。

4. 数据处理的两个基本问题

  计算机是进行数据处理的机器。那么在获取数据和处理数据时必然要明确两个问题:数据从哪里获取和获取多少数据,也就是数据的位置和数据的长度,

4.1 数据的位置

  绝大多数指令进行的是数据的处理,而处理可以大致分为三类:读取、写入和运算。在机器指令的层面上,我们大多时候注意的是指令执行的前一刻,它要处理的数据所在的位置。有三种可能性——CPU内部内存端口。比如,对于立即寻址的操作数,数据就在CPU内部的指令缓冲器中;对于直接寻址的操作数,数据就在CPU内部的寄存器中;对于寄存器间接寻址的操作数,数据就在内存中。等等。关于具体寻址方式,上面已经说的很详细了。

4.2 数据的长度

  8086CPU可以处理两种长度的数据,字节型(byte)和字型(word)。所以在指令中要指明,指令进行的是字操作还是字节操作。具体的方法如图2.4所示。


操作数长度的确定

图2.4 操作数长度的确定

猜你喜欢

转载自blog.csdn.net/kidthephantomthiefI/article/details/77172772