• Home
  • About
    • Road to Coding photo

      Road to Coding

      只要那一抹笑容尚存, 我便心无旁骛

    • Learn More
    • Email
    • Github
  • Posts
    • All Posts
    • All Tags

汇编语言(二)_寄存器

21 Nov 2017

上一章介绍了汇编语言的基本知识,这一章开始我们深入的理解汇编语言最常操作的寄存器

1. 寄存器

接着上一章的内容,我们现在来剖析一下CPU中所包含的内容:

  • 运算器: 进行信息处理

  • 寄存器: 进行信息的存储

  • 控制器: 控制这个各个器件进行工作

  • 内部总线,连接内部的部件.外部总线,连接CPU与主板上的其他部件,并且进行数据之间的传送

而对于汇编语言来讲,我们最常操作的就是寄存器(Register)了

8086CPU总共有14个寄存器,AX,BX,CX,DX,CS,DS,SS,ES,IP,SP,BP,SI,DI,PSW

1.1 通用寄存器

8086CPU中所有的寄存器都是16位的,AX,BX,CX,DX为通用寄存器

同时,为了处理兼容的问题,8086CPU的所有寄存器都可以拆成2个8位寄存器来进行使用

Tips: 8086CPU的寄存器可以拆成两个8位寄存器使用

因为8086CPU的上一代产品(具体叫什么忘了)的原因,8086相对于上一代产品,仅仅做了

寄存器位数上的升级,指令基本没有变化.

所以为了兼容的问题,8086每个寄存器可以拆成两个8位使用

即:

  • AX = AH + AL

  • BX = BH + Bl

  • CX = CH + CL

  • DX = DH + DL

CPU名称的记法,可以根据位的高低,AH(High),高8位.AL(low),低8位

Tips:在汇编语言中的进制

汇编中,我们经常要操作的是寄存器,而寄存器基本都是8位和16位.

所以,我们常用的进制是二进制和十六进制,B表示二进制,H表示十六进制,例: 1001B,02E3H

1.2 寄存器中存储的数据

在计算机的进制单位中,经常操作的是字节与字,之前也进行过相关进制的描述

字节:1 Byte,一次可以由一个8位寄存器进行控制

字: word,为两个字节,每次可以由1个16位寄存器进行控制

那么,问题来了,对于一个字,在16位仅存其中是如何存储的?

在计算机的发展史上,关于数据如何在元件中存储也是一个经典问题

随着,存储器的规模越来越大,这成为了一个不得不考虑的问题

对于少字节的数据,如何在计算机中存储

大端,小端两种模式应运而生

**大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中 **

大端模式和我们的阅读习惯一致。

**小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中 **

这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

很显然的,8086CPU属于** 小端模式 **

1.3 汇编指令

说了这么久,终于看到直观的汇编指令了

汇编指令 控制操作 高级语言语法描述
mov ax,18 将18送入寄存器ax AX=18
add ax,8 寄存器AX中的内容加上8 AX += 8
mov ax,bx 寄存器BX中的内容送入寄存器AX AX = BX
add ax,bx 寄存器AX中的内容加上BX中的内容 AX += BX

在汇编指令中,大小写不进行区分,效果相同

下面提到两个在进行进制计算的重要问题:

1.在出现数据溢出时:

如上例,AX,BX的求和结果,应该是1044CH,但是16位寄存器只能存储4位16进制数

所以,AX最后的值位044CH,而不是1044CH,

2.在进行8位寄存器操作时

mov al,85H
add al,93H

上面两条指令的结果是什么呢?

根据进制计算,al的结果是108H,

但是,实质上,最后在寄存器AL中存储的是08H

那么这是为什么呢?

因为AL是AX的低8位,所以AL只是一个8位的寄存器,不能存储3位的16进制数据

能进位吗? 不能,因为AL与AX并无直接关系,这一条add指令进行的是8位运算,不能进位到AH中

**所以,进行数据传送或者运算时,注意指令的两个操作对象是一致的 ! **

8位都是8位,16位都是16位

2. 物理地址

正如之谈到的一样,计算机所有的RAM与ROM抽想成为内存地址空间

所以,我们可以进行访问的内存实际上是线性的,即每个内存单元都有其唯一的物理地址

下面就来看看8086CPU如何生成16位的物理地址

Tips: 16位结构(16位机,字长为16)

16这个数字,在这里描述的是1个CPU的结构特性:

  • 运算器一次性可以处理16位的数据
  • 寄存器的最大宽度为16位
  • 寄存器与运算器之间的通路是16位

总结一下:在8086CPU的内部,一次性可以传输,存储,计算的数据为16位

同时,16一般指CPU通用寄存器的宽度

8086CPU有20位地址总线,,理论上是1MB的寻址空间

但是,8086实际上是16位CPU,所以能生成的寻址宽度,只有64KB

那么,如何实现1MB的寻址空间呢?

伟大创造:使用两个16位寄存器,生成20位的物理地址

来看一张图:

我们来看一看在8086CPU中,当要读写内存时:

  1. CPU中的相关部件提供两个地址,一个CS段地址(Code),一个IP偏移地址(instrument)

  2. 段地址与偏移地址通过,内部总线送入地址加法器中,

  3. 地址加法器将两个16位地址合并成为一个20位的物理地址

  4. 地址加法器通过内部总线将20位物理地址送入输入输出控制电路

  5. 输入输出控制电路将物理地址送上地址总线(外部总线)

  6. 20位物理地址被地址总线送往存储器,之后进行数据的操作

地址加法器: 物理地址 = 段地址 x 16 + 偏移地址

为什么乘16,因为地址是16进制,即为扩大一个数量级,之后进行偏移

即可理解段地址与偏移地址的含义

2.1 “段地址 x 16 + 偏移地址 = 物理地址” 的本质含义

套用王爽老师,进行解释的例子,

使用这种段地址 + 偏移地址进行寻址的方法 原因就是:

因为手头只有16位的寄存器,但是为了更高效率的寻址

同时,还要保证每一个内存单元都可以寻址到,就是用了这样的一种方法

在基础地址上进行偏移,可以实现访问尽可能多的地址空间,而且,每一个内存单元,都要保证能访问到

2.2 段的含义

上面说了很多的,段的概念,需要注意的是:

**实质上,内存中是没有进行分段的 ! **

所谓的段,是有程序员进行程序设计,操作内存时,自行进行分段的

来看一个例子:

Physical Address       CS         IP
	21F60H			2000H      1F60H
					  2100H      0F60H
					  21F0H      0060H
					  21F6H      0000H
					  1F00H      2F60H

上面的例子便可以看出,实质上每一个物理地址,可以有多组段地址 + 偏移地址实现访问同一物理地址

所以,段并非是处理器CPU自己进行划分的,实质上是程序员根据程序设计的需要,进行段的划分

所以,在进行编程时,我们可以根据需要进行段的划分

但是,需要注意的是:

1. 段地址一定是16的倍数,因为 X 16

2. 偏移地址只能达到64KB的寻址能力,因为偏移地址,也是一个16位寄存器存储的值,寻址能力只有64KB

寻址范围: 0000H ~ FFFFH

可以将地址连续,起始地址为16倍数的一组内存单元,视为一个段

2.3 段寄存器

现在开始,来介绍另外一类十分重要的寄存器,段寄存器

之前我们介绍的都是通用寄存器,而这些段寄存器,都有着其重要的作用

既然名为段寄存器,那么,这些寄存器中存储的都是段地址的信息,

DS: 数据段地址 (Data)

CS: 指令/代码段地址 (Code)

SS: 栈端段地址 (Stack)

目前常用的是这三个. . . (另外还有一个ES)


CS 与 IP这两个寄存器是8086CPU中最为重要的寄存器之二,CS为代码段寄存器,IP为指令指针寄存器

我们经常要表示当前CPU要执行的指令,就是使用CS,IP进行指向的

**常用表述方法 : **

1.执行CS:IP地址单元开始的指令,

2.或者代码存在CS段中的IP单元中

具体CPU如何读取和执行指令的流程,参考 < 汇编语言 > ( 王爽 ) P26 ~ P31

Tips: CPU如何将内存中的数据视为指令

之前我们曾经说过,CPU将内存中的数据,可以视为代码,数据,或是栈内数据

那么这一切都是如何进行界定的?

很简单:依靠段寄存器,进行识别,数据在内存中没有指令,数据之分,一切都是依靠CPU中的段寄存器

CPU通过修改CS,DS,SS,IP,SP这些寄存器中的内容,使得

CS:IP 内存单元中的数据被视为指令

DS:[x] 内存单元中的数据视为数据

SS:SP 内存单元中的内容视为栈内数据

内存中都是数据,没有指令,数据之分.划分是依靠处理器CPU如何进行代码段的读取界定的

2.4 修改CS,IP的指令

程序员对于处理器唯一能够进行操作的就是寄存器,

而我们通常进行寄存器内容修改的指令便是 mov指令

mov 指令 可以进行寄存器中指的修改.

但是,8086CPU中不能使用mov指令进行段寄存器的修改,因为处理器设计时,就没有提供这样的功能

其中提供了,除传送指令(mov)外的另外一类指令,转移指令

jmp CS:IP           使当前指令跳转至CS:IP处
jmp ax              使当前IP跳转至ax处

最后还是要强调一个概念:内存中,所有的东西,都是数据.到底是指令,还是数据,由CPU来定

使用Debug进行汇编语言的学习,这里的Debug并非是改Bug的意思,实际上是指进行交互式的程序

可以查看内存中的情况,同时还可以查看CPU寄存器中的内容

常见命令:

命令 功能
-R 查看,改变CPU中寄存器的内容
-D 查看内存中的内容
-E 改写内存中的内容
-U 翻译机器指令
-T 单步执行指令
-A 以汇编指令进行指令的输入


Assembly Share Tweet +1