汇编语言(第三版)读书笔记 2 - 第2章 寄存器

第2章  寄存器

前一章所说的总线,相对于CPU内部来说是外部总线。内部总线实现了CPU内部各个器件(运算器,控制器,寄存器)之间的联系,外部总线实现了CPU和主板上其他器件的联系。

不同的CPU,寄存器的个数、结构是不相同的。8086 CPU有14个寄存器,每个寄存器有一个名称,它们是AX, BX, CX, DX, IP, PSW, CS, DS, SS, ES, SP, BP, SI, DI。

2.1.   通用寄存器

8086 CPU的所有寄存器都是16位的,可以存放两个字节。AX, BX, CX, DX这4个寄存器通常用来存放一般性的数据,被称为通用寄存器

汇编语言(第三版)读书笔记 2 - 第2章 寄存器_第1张图片

图 2.1 – 2.1 16位寄存器的逻辑结构

4个通用寄存器都可以分为两个可独立使用的8位寄存器来用。如AX可分为AHAL两个。其中,AX的高8位(8-15位)构成了AH寄存器,低8位(0-7位)构成了AL寄存器。AHAL均可独立使用

个人注:目前CPU已经从16位,32位发展到了64位,这些通用寄存器也经历了AH/AL(8), AX(16), EAX(32), RAX(64)的发展,他们之间的关系如下图:


图 2.2 - ah al, ax, eax, rax的关系(网摘)

即:AH, AL分别是AX的高8位和低8位,AX是EAX的低16位,EAX是RAX的低32位。

2.2.   字在寄存器中的存储

出于对兼容性的考虑,8086 CPU可以一次性处理以下两种尺寸的数据:

字节记为byte一个字节由8bit组成,可以存在8位寄存器中。

记为word一个字由两个字节组成,这两个字节分别称为这个字的高位字节和地位字节。

2.3.   几条汇编指令

1)汇编指令(包括寄存器名称)不区分大小写,如mov ax,18和MOV AX,18含义相同。

2)当单独使用AL/AH时,是把它作为一个独立的8位寄存器来使用的,此时它与AH/AL没有任何关系。如在执行下面语句时:

mov ax,0

mov al,C5H

add al,93H

首先设置AX的值为0,设置AL的值为C5H,而后将AL的值加上93H,而C5H+93H=158H,此结果已经超出了AL的取值范围,此时由于只单独对AL进行操作,故AH和AL是两个不相关的寄存器,故最终的执行结果是AX的值为0058H,而并不是0158H。不要错误的认为产生的进位会存储在AH中。

需要注意的是,虽然进位值丢失(丢失是指该进位值不能在8位寄存器中保存),但CPU并没有真的丢弃这个进位值,此问题将在后面进行讨论。

3)在进行数据传送或运算时,要注意指令的两个操作对象的位数应当是一致的。如:

mov ax,bx

mov bx,cx

mov ax,18H

mov al,18H

add ax,bx

add ax,20000

等都是正确的指令。而:

mov ax,bl     (在8位寄存器和16位寄存器之间传送数据)

mov bh,ax     (在16位寄存器和8位寄存器之间传送数据)

mov al,20000  (8为寄存器最大可存放值为255的数据)

add al,100H      (将一个高于8位的数据加到一个8位寄存器中)

等都是错误的指令,错误的原因都是指令的两个操作对象的位数不一致。

2.4.   物理地址

每一个内存单元在内存地址空间中都有唯一的地址,该地址被称为物理地址不同的CPU可以有不同的形成物理地址的方式

2.5.   16位结构的CPU

16位CPU结构(16位机,字长为16位等常见说法,与16位结构的含义相同),描述了一个CPU具有下面几方面的结构特性:

寄存器的最大宽度为16位;

寄存器和运算器之间的通路为16位;

运算器一次最多可以处理16位的数据;

808616位结构的CPU,即指在CPU内部,能够一次性处理、传输、暂时存储的信息的最大长度是16位的。内存单元的地址在送上地址总线之前,必须在CPU中处理、传输、暂时存放。

2.6.   8086 CPU给出物理地址的方法

8086 CPU的地址总线为20,可以传送20位地址,达到1MB寻址能力。而8086 CPU本身又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。所以,如果只是将地址从CPU内部简单的发出,那么它只能送出16位的地址,由此表现出来的寻址能力应该是64KB,明显与实际情况不符。为什么?

原来,8086 CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。如下图:

汇编语言(第三版)读书笔记 2 - 第2章 寄存器_第2张图片

图 2.3 - 2.6 8086CPU相关部件的逻辑结构

地址加法器采用“物理地址 =基础地址(段地址*16+偏移地址”的方法用段地址偏移地址合成物理地址

2.7.   “基础地址(段地址*16)+ 偏移地址 = 物理地址”的本质含义

“物理地址 = 基础地址(段地址*16)+ 偏移地址”的本质含义是:CPU在访问内存时,用一个基础地址(段地址*16)和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。

更一般地说,8086 CPU的这种寻址功能是“基础地址+偏移地址=物理地址”寻址模式的一种具体实现方式。8086 CPU中,“段地址*16”可以看做“基础地址”。

2.8.   段的概念

内存并非被划分成了一个一个的有各自段地址的段。实际上,内存并没有分段,段的划分来自于CPU

l  内存单元地址小结

1) CPU访问内存单元时,必须向内存提供内存单元的物理地址。8086 CPU在内部用段地址和偏移地址移位相加的方法形成最终的物理地址

2) CPU可以用不同的段地址和偏移地址形成同一个物理地址,如:

段地址:偏移地址2000H:1F60H和2100H:0F60H,都可表示物理地址21F60H;

3) 8086 PC机中,存储单元的地址用两个元素来描述,即段地址和偏移地址。

“数据在21F60H内存单元中”,这句话对于8086 PC机一般不这样讲,取而代之的是两种类似的说法:

1数据存在内存2000:1F60单元中;

2数据存在内存的2000H段中的1F60单元中;

4) 可以根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段

2.9.   段寄存器

段地址在8086 CPU的段寄存器中存放。8086 CPU有4个段寄存器:CS, DS, SS, ES

2.10.   CS和IP

CS和IP是8086 CPU中两个最关键的寄存器,它们指示了CPU当前要读取指令的地址。CS为代码段寄存器,IP为指令指针寄存器。

在8086 PC机中,设CS中的内容为M,IP中的内容为N,任意时刻,8086 CPU将从内存M*16+N单元开始,读取一条指令并执行

也可以这样表述:8086机中,任意时刻,CPUCS:IP指向的内容当做指令执行

8086 CPU的工作过程可以简要描述如下:

1) CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;

2) IP=IP+所读取指令的长度,从而指向下一条指令;

3) 执行指令。转到步骤1),重复这个过程;

8086 CPU加电启动或复位后(即CPU刚开始工作时)CSIP被设置为CS=FFFFHIP=0000H,即在8086 PC机刚启动时,CPU从内存FFFF0H单元中读取执行执行,FFFF0H单元中的指令是8086 PC机开机后执行的第一条指令。

问:CPU根据什么将内存中的信息看做指令?答:CPU将CS:IP指向的内存单元中的内容看做指令。

2.11.   修改CS、IP的指令

MOV指令不能用于设置CSIP的值,因为8086 CPU没有提供这样的功能。能够改变CS,IP内容的指令被统称为转移指令。下面讲解一下转移指令中的JMP指令。

2.11.1  JMP指令

l  JMP 段地址:偏移地址

含义:将CS的值修改为指令中给定的段地址,IP则修改为给定的偏移地址;

例:JMP 2AE3:3

执行后:CS=2AE3H,IP=0003H;

l  JMP 立即数

含义:将IP的值修改为指令中给定的立即数;

例:JMP 0

执行后:CS值保持不变,IP=0000H;

l  JMP 内存单元

含义:将IP的值修改为指令中给定的内存单元的值;

例:JMP [0]

执行后:CS值保持不变,IP=地址为DS:[0]处的内存值;

l  JMP 通用寄存器

含义:将IP的值修改为指令中给定的寄存器的值;

例:JMP AX

执行后:CS值保持不变,IP=寄存器AX中的值;

2.12   代码段

将一段内存当做代码段,仅仅是我们在编程时的一种安排,CPU并不会由于这种安排,就自动地将我们定义的代码段中的指令当做指令来执行。CPU只认被CS:IP指向的内存单元中的内容为指令。所以,要让CPU执行我们放在代码段中的指令,必须要将CS:IP指向所以应的代码段中的第一条指令的首地址。

2.13  查看CPU和内存,用机器指令和汇编指令编程

Debug是DOS、Windows都提供的实模式(8086方式)程序的调试工具。使用它,可以查看CPU各种寄存器中的内容、内存的情况和在机器码级跟踪程序的运行。

Debug的功能

1) 用Debug的R命令查看、改变CPU寄存器的内容;

l  直接执行r命令,显示所有寄存器的值,在所有寄存器的下方,还列出了CS:IP所指向的内存单元处所存放的机器码,并将它翻译为汇编指令;

l  r 寄存器名– 修改给定寄存器的值;

2) 用Debug的D命令查看内存中的内容:

l  直接执行d命令,默认从预设地址开始显示;

l  d 段地址:偏移地址– Debug将列出从指定内存单元开始的128个内存单元的内容;

l  d 段地址:起始偏移地址结尾偏移地址– 查看指定范围的内存单元;

l  执行完上面3条命令任意一条后,接着直接使用d命令,可列出后续的内容;

3) 用Debug的E命令改写内存中的内容:

l  直接执行e命令报错,后面必须写内存地址;

l  e 段地址:偏移地址[数值|字符|字符串] [数值|字符|字符串] [数值|字符|字符串]… - 向内存写入数值、字符或字符串,其中字符及字符串前后要加上单引号或双引号,数值前后则无需引号;

eg: 命令:e1000:0000 ‘a’ 1 “a+b”

说明:改写内存1000:0000至1000:0004的值为a,1,a,+,b

l  e 段地址:偏移地址 - 采用提问的方式来一个一个地改写内存中的内容;

4) 用Debug的U命令将内存中的机器指令翻译成汇编指令:

l  直接执行u命令,默认从预设地址开始显示;

l  u段地址:偏移地址– Debug将从指定内存单元开始将机器指令翻译成汇编指令;

l  u 段地址:起始偏移地址结尾偏移地址– 将指定范围内存单元中的机器指令翻译成汇编指令;

l  执行完上面3条命令任意一条后,接着直接使用u命令,可列出后续的内容;

l  u命令的输出共三列,分为三个部分,三列依次为“每一条机器指令的地址”、“机器指令”、“机器指令对应的汇编指令”;

5) 用Debug的A命令以汇编指令的格式在内存中写入一条机器指令:

l  直接执行a命令,默认从预设地址开始;

l  a 段地址:偏移地址– Debug将从指定内存单元开始将汇编指令写入到内存;

l  在给出的起始地址后直接按Enter键表示操作结束;

l  使用a命令输入的是汇编指令,Debug将这些汇编指令翻译为对应的机器指令,并将它们的机器码写入内存;

6) 用Debug的T命令执行一条机器指令:

l  直接执行t命令,执行当前CS:IP所指向的指令;

l  t 立即数– 从CS:IP所指命令开始,执行3条汇编指令;

l  若要用t命令执行非CS:IP所指的指令,则需要先使用r命令修改CS和IP的值,把他们的值修改为要执行的指令的地址,再使用t命令执行;

l  执行完上面3条命令任意一条后,接着直接使用t命令,可依次执行下一条指令;

l  每次使用t命令执行一条汇编指令后,IP的值一般都会发生变化;


 

你可能感兴趣的:(汇编语言)