ToB企服应用市场:ToB评测及商务社交产业平台

标题: 8086 汇编语言知识点梳理 [打印本页]

作者: 伤心客    时间: 2023-11-23 13:50
标题: 8086 汇编语言知识点梳理
基础知识

机器语言

汇编语言

汇编语言的组成

汇编语言的种类

汇编无法得到高级语言,因为不同高级语言在汇编上是相同的
总线

总线是一根根导线的集合
每一个CPU新片都有许多管脚,这些管脚和总线相连,CPU通过总线和外部器件进行交互。
总线的分类

地址总线:寻址,找到地址对应的存储空间

地址总线决定了CPU的寻址能力,8086地址总线宽度是20,所以它的寻址能力是1M $(2^{20})$
寻址能力的计算:首先明白总线就是导线,导线能够传递的是电信号,电信号分为两种:高电平信号、低电平信号,高电平信号即 1,低电平信号即 0。假如总线总线的宽度是 3 ,那么 3 根导线高电平为 1 ,低电平为 0 ,它们最大能够传递的值只有 $2^3$ 种:000,001,010,011,100,101,110,111。
数据总线:传递,CPU和内存之间传递具体数据

数据总线决定了CPU单次数据的传送量,也就是数据传送的速度。8086的数据总线宽度是16,所以单次最大能够传递2个字节的数据。
单次数据传送量的计算:数据总线的宽度是16,同地址线一样,16根线代表16位0或1,即16位二进制数据,一次最多能够传送16个二进制位。一个字节是8位,16位即2个字节。所以8086单次能够传递的最大数据量就是2个字节。
8088的数据总线宽度是8,8086的数据总线宽度是16,分别向内存中写入89D8H时(89D8H即16进制的89D8,汇编语言中末尾加H代码16进制)。一个16进制代表4个二进制位,两个16进制代表8个二进制位即1个字节,四个16进制即2个字节。因为8088数据线宽度是8,一次只能传递一个字节,所以8088传递89D8H需要传2次,第一次传D8,第二次传89。而8086只需要一次就能够将89D8传递完成。
控制总线:控制,告诉内存需要进行读还是写操作

控制总线决定了CPU的控制能力,代表CPU有多少种控制能力。
CPU从内存中读取数据的步骤

CPU 如何控制外设

CPU通过总线向接口卡发送命令,接口卡根据命令控制外设工作
内存

所有的内存单元都有唯一的地址,这个地址叫做物理地址。
8086CPU的地址总线是20根,那么它能够访问的内存空间的地址值范围即 0x00000 - 0xFFFFF(上面已经说明过,一个16进制位=4个二进制位),通过这个范围可以定位  $2^{20}$ 个不同的内存单元,所以8006的内存空间大小为1M。

8086的寻址方式

上面提到8086的地址总线宽度为20,寻址能力为1M,但是实际上8086是一个16位架构的CPU,它内部能够一次性处理、传输、暂存的数据只有16位。这就意味这8086实际上只能够直接送出16的地址,但是它的地址总线宽度又是20位,意味这这样就有4位是无法使用的,它的实际寻址能力只能够是64KB。那么它是如何做到实现1M的寻址能力呢,具体步骤如下:
字节与字

汇编语言没有数据类型的概念,它是直接操作内存的,汇编语言的数据存储单位有两个:
寄存器

寄存器是CPU非常重要的部件,可以通过改变寄存器的值来实现对程序的控制。不同CPU的寄存器个数和结构一般都不相同,下面是8086CPU寄存器的结构,8086CPU有14个寄存器,所有寄存器都是16位的。
字在寄存器中的存储

在CPU中,16位寄存器存储一个字,高八位存储高位字节,低八位存储地位字节
在内存中,字的地位字节存放在低地址单元,高位字节存放在高地址单元
数据寄存器

数据寄存器由AX(Accumulator Register)、BX(Base Address Register)、CX(Count Register)、DX(Data Register)组成,虽然上图里边每个每一个寄存器都分成了两块,但它依然是一个寄存器。
由于8086之前的CPU是8位的架构,所以8086为了兼容8位的程序,每个16位数据寄存器都可以当作两个单独的8位寄存器来使用。AX寄存器可以分成两个独立的8位寄存器,高8位为AH,低8位为AL。BX、CX、DX同理。
除了四个数据寄存器之外,其它的寄存器均不可以分为两个独立的8位寄存器。独立的意思是:当AH和AL做为8位寄存器使用时,可以看作它们是互不相关的,形式上可以看作两个完全独立的寄存器。
既然数据寄存器可以当作两个独立的寄存器,那么它们既可以用整个寄存器的16位存放一个数据,也可以高8位和低8位分别存放一个数据共存放两个数组。
AX(accumulate)

AX 作为累加器用,所以它是算术运算的主要寄存器。在乘、除等指令中指定用来存放操作数。
另外,所有的I/O指令都使用这一寄存器与外部设备传送信息。
BX(base)

BX 在计算存储器地址时,它经常用作基址寄存器。
CX(count)

CX 常用来保存计数值,如在移位指令、循环和串处理指令中用作隐含的计数器。
DX(data)

DX 一般在作双字长运算时把DX和AX组合在一起存放一个双字长数,DX用来存放高位字。
此外,对某些I/O操作,DX可用来存放I/O的端口地址。
段寄存器(Segment Register)

前面关于8086的寻址方式里边提到,8086需要16位的段地址和偏移地址合成20位地址,其中的段地址就由段寄存器提供。段寄存器一共有四个,每个段寄存器的作用都不相同。
CS 代码段寄存器(Code Segment Register)

CS和IP配合使用,它们指示了CPU当前要读取指令的地址。任何时候,8086CPU都会将CS:IP指向的指令做为下一条需要取出执行的指令。
指令执行的过程:
在内存或者磁盘上中,指令和数据没有任何区别,都是二进制信息。 CPU在工作时,有时候把信息当作指令,有时候看作数据,同样的信息赋予不同的意义。
CPU根据什么将内存中的数据信息当作指令? 通过CS:IP指向的内存单元内容看作指令。
DS 数据段寄存器(Data Segment Register)

DS是用来操作内存时提供段地址的,假如需要将内存中10000H 存入1122H,直接这样写是不可以的:
  1. mov 1000H:[0H],1122H
复制代码
因为汇编语言又如下要求:
正确做法是:
  1. mov ax,1000H
  2. mov ds,ax
  3. mov [0H],1122H
复制代码
SS 堆栈段寄存器(Stack Segment Register)

配合SP使用,SS:SP指向栈顶元素
其他寄存器

SI 源变址寄存器(Source Index Register)

一般与DS联用,用来确定数据段中某一单元的地址
与自动增量和自动减量的功能,方便用于变址
DI 目的变址寄存器(Destination Index Register)

与SI相同
BP 基址指针寄存器(Base Pointer Register)

可以作为堆栈区中的一个基地址以便访问堆栈中的信息
8086专用寄存器

IP 指令指针寄存器(Instruction Pointer Register)

它用来存放代码段中的偏移地址。在程序运行的过程中,它始终指向下一条指令的首地址,它与段寄存器CS联用确定下一条指令的物理地址。当这一地址送到存储器后,控制器可以取得下一条要执行的指令,而控制器一旦取得这条指令就马上修改IP的内容,使它指向下一条指令的首地址。
可见,计算机就是用IP寄存器来控制指令序列的执行流程的,因此IP寄存器是计算机中很重要的一个控制寄存器。
SP 堆栈指针寄存器(Stack Pointer Register)

存放栈顶的偏移地址
FLAGS 标志寄存器 / PSW 程序状态寄存器(Program Status Word Register)

存放条件码标志,控制标志和系统标志
条件码标志

条件码标志用来记录程序中运行结果的状态信息,它们是根据有关指令的运行结果由CPU自动设置的。由于这些状态信息往往作为后续条件转移指令的转移控制条件,所以称为条件码。它包括以下6位:
控制标志

控制标志位为方向标志(direction flag,DF),在串处理指令中控制处理信息的方向用。
系统标志

系统标志位可以用于I/O、可屏蔽中断、程序调试、任务切换和系统工作方式等的控制。一般应用程序不必关心或修改这些位的状态,只有系统程序员或需要编制低层I/O 设备控制等程序时才需要访问其中的有关位。
规范与约定

[...]

(汇编语法规定)表示一个内存单元
一个内存单元的描述:
(...)

(为了学习方便规定)表示一个内存单元或寄存器中的内容
idata

表示常量,某个字符
访问内存

为了访问内存,我们可以使用这四个寄存器:BX,SI,DI,BP
我们可以使用如下方式访问对应地址:

除了BP寄存器,其他寄存器默认均使用DS寄存器,BP使用SS寄存器

BP不能和BX一起作为偏移地址,SI不能和DI一起作为偏移地址
段寄存器中的值成为 段地址 ,通用寄存器中的值称为 偏移地址
类型

为了告诉编译器数据类型,需要使用以下前缀:
byte ptr

字节
word ptr


MOV 指令

mov 指令将第二个操作数(源)复制到第一个操作数上(目标)
MOV 指令支持以下指令形式:
REG:AX,BX,CX,DX,AH,AL,BH,BL,CH,CL,DH,DL,DI,SI,BP,SP
memory:[BX],[BX+SI+7],variable
immediate: 5, -24, 3Fh, 10001101b
对于段寄存器只有以下指令可以使用:
SREG: DS, ES, SS, and only as second operand: CS.
  1. ; 假设内存10000H原始值: 1122H
  2. ; 8086是小端模式,高字节放在高地址,低字节放在低地址
  3. ; 1000:0000  22
  4. ; 1000:0001  11
  5. ; 准备修改10000H位置的值
  6. mov ax, 1000H
  7. mov ds, ax
  8. ; 1000:0000  66
  9. ; 1000:0001  11
  10. ; 修改后10000H: 1166H
  11. mov [0], 66h
  12. ; 1000:0000  66
  13. ; 1000:0001  11
  14. ; 修改后10000H: 1166H
  15. mov byte ptr [0], 66h
  16. ; 1000:0000  66
  17. ; 1000:0001  00
  18. ; 修改后10000H: 0066H
  19. mov word ptr [0], 66h
复制代码
寻址方式

当数据存放在内存中的时候,我们可以用多种方式来给定这个内存单元的偏移地址,这种定位内存单元的方法一般称为寻址方式。
数据有关的寻址方式

隐含寻址

隐含寻址就是指令中不指明操作数,但隐含在操作码中。如乘法指令(MUL src)
立即数寻址(immediate addressing)

操作数直接包含在指令中,紧跟在操作码之后的寻址方式称为立即寻址方式,把该操作数称为立即数。
例:
MOV AL,2CH
MOV AX,2C40H
寄存器寻址

操作数包含在CPU内的某个寄存器中,指令直接给出寄存器名。
例:
INC CX
MOV AX,BX
存储器寻址

除以上三种寻址方式外,以下各种寻址方式的操作数都在存储器中,其操作数称为存储器操作数。
由于80X86对内存采用分段管理,因此由以下寻址方式得到的只是有效地址(简写为EA-effective address,在IBM PC中就是操作数地址的偏移量部分)。
有效地址可以由以下四种成分组成:
EA = 基址 + 变址 + 位移量
直接寻址

操作数的有效地址直接包含在指令中的寻址方式。
有效地址存放在代码段的指令操作码之后,但操作数本身在存储器中,所以必须先求出操作数的物理地址。这种寻址方式常用于存取简单变量。
例:
MOV AL, [1400H]
由于在汇编语言中用符号表示地址,所以指令“MOV AL,VAR”中的源操作数寻址方式是直接寻址,有时也写做“MOV AL,[VAR]”
寄存器间接寻址

操作数的有效地址在基址寄存器BX、BP或变址寄存器SI、DI中,而操作数在存储器中的寻址方式
例:
MOV AX, [DI]
寄存器相对寻址

也称为直接变址寻址方式。操作数的有效地址是一个基址(BX、BP)或变址(SI、DI)寄存器的内容和指令中给定的一个位移量(disp)之和。有效地址由2部分组成。
例:
MOV AX, [DI+0100H]
基址变址寻址

操作数的有效地址是一个基址寄存器(BX、BP)和一个变址寄存器(SI、DI)的内容之和。缺省使用段寄存器的情况由基址寄存器决定。
例:
MOV AX, [BX] [SI] ← → MOV AX, DS: [BX+SI]
相对基址变址寻址

操作数的有效地址是一个基址和一个变址寄存器的内容和指令中给定的一个位移量之和。有效地址由三部分组成。缺省使用段寄存器的情况由基址寄存器决定。
例:
MOV AX, 06H[BX+SI] ← → MOV AX, DS:[BX+SI+06H]
与转移地址有关的寻址方式

这种寻址方式用来确定转移指令及CALL指令的专项地址

非考点,略
变量

变量是一种内存地址
8086的汇编器支持两种类型的变量:BYTE 和 WORD
声明一个变量的方式如下
  1. name DB value                ;DB 表示字节 Define Byte
  2. name DW value         ;DW 表示单字 Define Word
  3. name DD value         ;DD 表示双字 Define Double(Word)
  4. ; name 可以是任何字符和/或数字的组合,但是它必须以一个字符开始
  5. ; 可以声明一个未命名的变量(变量会拥有一个地址,但是没有名字)
  6. ;value 可以是任何数字或者是 '?' 表示未初始化
复制代码
数组

数组可以被视为一系列变量,下面是一些数组声明的例子:
  1. a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h
  2. b DB 'Hello', 0
复制代码

你可以通过方括号来访问数组中的任何元素
  1. MOV AL,a[3]
复制代码
你还可以使用任何内存索引寄存器 BX,SI,DI,BP 来访问其中的元素
  1. MOV SI,3
  2. MOV AL,a[SI]
复制代码
DUP

如果需要声明一个一个大数组,可以使用DUP操作符
number DUP (value(s))
number —— 需要声明的复制(任何常数)
value —— 将要复制的值
如果你想要声明一个比255更大或比-128更小的值,你可以使用DW取代DB。注意:DW 不能被用来声明字符串
获得变量的地址(LEA,OFFSET)

你可以通过两种方式获得变量的地址:LEA(Load Effective Address)指令和它的替代品 OFFSET 操作符
LEA 同时还能让你获得索引变量的地址。
LEA和OFFSET最后都会被编译为同一种机器语言:
MOV BX,num
num是一个16进制的偏移量
注意:只有以下寄存器可以被用在方括号内(作为内存指针):BX,SI,DI,BP
LEA

<ul>格式:LEA REG,SRC

操作:(REG)




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4