汇编笔记

Posted by Wh0ami-hy on October 24, 2021

笔记根据王爽写,文末总结有指令查询手册

1. 什么是汇编

汇编语言提供了一种直接操控CPU、寄存器和内存的工具

2. 第一章

2.1. 数的表示

在汇编语言中, 数值后面分别用字母B代表二进制(Binary)、 H代表十六进制(Hexadecimal)、 D 代表十进制(Decimal)(十进制数可以省略D)

2.1.1. 进制数三要素

  • 基数
  • 位权
  • 进位

2.1.2. 有符号数

0代表非负数,1代表负数

根据不同表示方式,分为原码、反码、补码

2.1.3. 无符号数

直接使用十六进制表示

2.1.4. 机器数

把正负号数值化后,得到的计算机能实际表示的数

包括:原码、反码、补码

2.1.5. 真值

带有正负号的实际数值

2.1.6. 内存中的数据(重点)

  • 数字

有符号数存放的是数字的补码的二进制,无符号数直接存放十六进制的二进制

  • 字符

存放的是字符对应的某种编码的二进制

2.1.7. 二进制数

从右向左分别为1位、2位、4位、8位、16位

2的n次方 大小
2^10 1024 = 1K
2^20 1024K = 1M
2^30 1024M = 1G
2^40 1024G = 1T

2.1.8. 十进制数

从右向左依次为个位、十位、百位、千位、万位

2.1.9. 十进制数和二进制数的关系

当二进制产生进位时,代表的十进制数为2、4、8、16、32、64、128

2.2. 进制转换

在计算机中, 数据都是以二进制表示的, 因此采用2的n次方形式描述数的权值大小。

2.2.1. 十进制与其他进制转换(重点)

十进制整数部分转换为其他进制数采用 “除基取余”法,直到商为0, 小数部分转换采用 “乘基取整”法

将十进制数58.125转换为二进制数

2.2.2. 二进制与其他进制转换(重点)

二进制转十进制

按权展开法,小数点前一位,权值为0,小数点后一位权值为-1

二进制数101101.18 转换为十进制数
101101.1 B = 1 x 2^5 + 0 x 2^4 + 1 x 2^3 + 1 x 2^2 + 0 x 2^1 + 1 x2^0 + 1 x 1^-1 =45.5 D

二进制转十六进制

每四位二进制数转为一位十六进制数。二进制数整数从小数点左边开始每4位一组, 小数则从小数点右边开始每4位一组, 不够位数以0补齐。

注意:整数位补0,对值没有影响,小数位补0对值有影响

101101 B = 0010 1101.1000 = 2D.8 H

2.2.3. 十六进制与其他进制转换

十六进制转换为十进制

按位权展开

十六进制数39C H转换为十进制数
按权展开:
39C H= 3 X 16^2 + 9 X 16^1 + 12 X 16^0 = 924 D

十六进制转换为二进制

每一位十六进制数转位四位二进制数,用四位二进制按权相加去凑这位十六进制数,小数点位置照旧

2.3. 进制运算

2.3.1. 二进制运算(重点)

加法

对于多位数二进制相加,考虑进位采用“逢2进1”的方式

有4种可能 0+0=0、0+1=1、1+0=1、1+1=10

减法

有4种可能 0-0=0、1-0=1、1-1=0、0-1=1(同时向高位借1,即看作是10 - 1,因为10 = 1+1,所以 10 -1 = 0-1 = 1)

乘法

如果是乘以2,那么只需要左移一位就可以,后面无论是正数还是负数,全部补0

除法

除以2时,向右移一位,如果这个数是正数,那么右移的时候左边补0。 如果这个数时负数,那么右移的时候左边补1

2.3.2. 十六进制运算

加法

减法

2.4. 补码(重点)

  • 汇编中数都是以补码的形式表示的
  • 有关补码的运算,要转为二进制再做计算

2.4.1. 原码

原码就是符号位加上真值的绝对值,即用第一位表示符号,其余位表示值

[+1]原 = 0000 0001

[-1]原 = 1000 0001

2.4.2. 反码

正数的反码是其本身

负数的反码是在其原码的基础上,符号位不变,其余各个位取反

[+1] = [00000001]原 = [00000001]反

[-1] = [10000001]原 = [11111110]反

2.4.3. 补码

正数的补码就是其本身

负数的补码是在其原码的基础上,符号位不变, 其余各位取反,最后+1(即在反码的基础上+1),或 用2^n - |X|表示负数X的补码,n二进制位数

[+1] = [00000001]原 = [00000001]反 = [00000001]补

[-1] = [10000001]原 = [11111110]反 = [11111111]补

8位二进制补码的范围

正数 
00000000 B - 01111111 B
00H - 7FH
0 - 127D

负数
10000000 B - 11111111 B
80H - FFH
-128D - -1D

2.4.4. 求补运算

对补码连同符号位一起求反,在末位加1,得到这个数相反数的补码。

即正数的补码求补得到其负数的补码,负数的补码求补得到其正数的补码

求补运算是一种数值运算方法,它与补码表示有所不同。在求补运算中,不考虑数的符号位,对所有位进行按位取反操作,并最后加一。它求得的结果不是求这个数的补码,而是这个数相反数的补码。

机器字长为8位,则-50D 的补码为:
   +50的补码为   0011 0010B
   按位求反后为: 1100 1101B
   末位加1 :     1100 1110B
   则[-50]补= 1100 1110 B=0CE H

2.4.5. 从补码求真值

正数直接从补码得到真值。负数补码的数值位求反,符号位变为负号,末位加1,就得到其真值

2.4.6. 补码的运算规则

 [A+B]补= [A]补+ [B]补

 [A- B]补= [A]补+ [-B]补

2.4.7. 引入补码的意义(重点)

统一了加法和减法运算:在计算机中,加法是一种基本的运算操作,而减法可以通过加法来实现。使用补码可以使加法和减法运算的处理方式保持一致。在补码表示中,减法运算可以转换为加法运算,简化了运算器的设计和实现。

消除了正负数的不对称性:在使用原码表示法时,正数和负数的表示形式不对称,这会给运算和比较操作带来复杂性。而使用补码表示法后,正数和负数的表示形式统一了,使得计算机可以使用相同的硬件逻辑来处理正数和负数的运算,简化了计算机的设计。

增加了数的表示范围:在使用补码表示法中,有限位数的二进制数可以表示更大的数值范围。例如,对于一个8位的二进制数,使用原码表示法可以表示-127到127的范围,而使用补码表示法可以表示-128到127的范围。补码表示法允许使用相同的数值位数表示更广泛的数值范围。

消除了零的重复表示:在使用原码和反码表示法时,零有两个不同的表示形式,即+0和-0,这会引起计算和比较操作的混乱。而在补码表示法中,零只有一种表示形式,消除了零的重复表示问题。

下面看计算十进制的表达式 1-1 = 1 + (-1) = 0的例子

  • 使用原码
1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
  • 使用反码
1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
  • 补码
1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原

这样0用[0000 0000]表示,而以前出现问题的-0则不存在了。而且可以用[1000 0000]表示 -128

(-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补

注意:-128并没有原码和反码表示。对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原,这是不正确的

2.5. 数的范围

2.5.1. 8位二进制所能表示的有符号数范围

[1111 1111 ,0111 1111]
即
[-127 ,127]

原码或反码表示的范围为[-127,+127],而使用补码表示的范围为[-128,127]

2.5.2. 8位二进制所能表示的无符号数范围

[0000 0000 , 1111 1111]
即
[0 , 255]

2.6. 双精度数

16位计算机表示32位数的时候,用两个字长,则称两个十六位数位双精度数

2.6.1. 字节(byte)

一个字节占8个二进制位(bit位)

2.6.2. 字

一个字等于两个字节

2.6.3. 字长

计算机一次可处理的二进制位数

2.7. 存储容量

2.7.1. 表示

存储容量可用存储字数(存储单元数)x存储字长表示

1MB = 1024KB = 1M x 8bit 

2.7.2. 换算

1k = 2^10 = 1024
1M = 2^20
1byte = 8bit
1kB = 1024byte

2.8. 符号位扩展

  • 首先要明确,是有符号数还是无符号数
  • 无符号数扩展,前面补充若干个0
  • 有符号数扩展,最高位是1,前面补充1,最高位是0,前面补充0

2.9. 进位

由于运算结果超出了位数最高有效位向前的进位,这一位自然丢失,但结果是正确的

2.10. 溢出

表示结果超出了字长允许表示的范围,一般会造成结果出错

  • 两个正数相加得到负数

  • 两个负数相加得到正数

2.11. 编码

所谓编码,就是采用按一定规则组合而成的若干位二进制码来表示数或字符

2.11.1. BCD码

  • 对十进制的10个数码用二进制编码表示
  • 只是看起来是用二进制编码表示0~9,在计算时,仍为二进制的计算,所以计算结果需要修正

分类

  • BCD码可以是8421码、2421码、余3码等

BCD码采用四位二进制数表示一位十进制数, 如果这四位二进制数的各位之权自左至右分别为8、4、2、I,则称为8421码

  • 压缩的:4位二进制数表示一位十进制数
85D = 10000101 = 85H

用4位二进制数表示一位十进制数,恰好可以用一位16进制数显示一位十进制数

  • 非压缩的:8位二进制数表示一位十进制数
85D = 000010000 00000101 = 0805H

非压缩的BCD码加上30H, 就转换成了该数字的ASCII码

2.12. ASCII码

  • 标准ASCII码采用7位编码,即一个字节的最高位0,共128种代码
  • 位数从0开始算起
大写字母A-Z: 41H-5AH 		
小写字母a-z: 61H-7AH 
数字0-9: 30H -39H	

空格: 20H 
回车: ODH 
换行: OAH 
响铃: 07H

3. 第二章

3.1. 计算机基本结构

3.1.1. 组成(五大件)

运算器、控制器、存储器、输入设备、输出设备

3.1.2. 总线

内部总线

CPU内部各个部件间的连线

外部总线(系统总线)

连接主板上各个部件的总线

总线的位数由CPU决定,如8086的地址总线为20位,数据总线为16位

  • 地址总线

它的宽度(也称为位数)决定了CPU的寻址能力,即CPU可以直接访问的内存或设备的地址范围。例如,如果计算机的地址总线宽度为32位,那么CPU可以寻址的内存或设备地址范围可以达到2^32个(约为4GB)

  • 数据总线

它的宽度决定了CPU一次可以传输的数据量。例如,如果计算机的数据总线宽度为16位,那么每次数据传输的量为16位(2个字节)。数据总线的宽度直接影响数据传输的速度和效率。

  • 控制总线

它的宽度决定了CPU对系统中其他设备的控制能力。控制总线传输的信号包括读写控制、中断请求、时钟同步、设备选择等。控制总线的宽度决定了CPU与其他设备之间的控制通路数量和功能。

3.1.3. 接口

外部设备和计算机主机间的中间缓存介质

并行接口

多个数据位同时通过多根数据线进行传输。每个数据位占用一根数据线,数据在并行接口中同时进行传输,从而实现高速数据传输。

如 8位数据用8根数据线传输

串行接口

串行接口使用较少的信号线来传输数据,通常只有一根数据线。每个数据位按照顺序依次传输,其中每个数据位之间可能会包含起始位、停止位和校验位等控制信号

3.2. 8086CPU

3.2.1. 组成

执行单元(EU)

算术逻辑运算单元(ALU)

标志寄存器

暂存器

寄存器组

控制单元

总线接口单元(BIU)

段寄存器组

指令指针寄存器IP

地址加法器

指令队列单元

总线控制系统

3.2.2. 内部

3.3. 8086寄存器

  • 计算机的字长和处理器的寄存器位数有关

  • 8086寄存器都是16位的

3.3.1. 数据寄存器

用来保存操作数或运算结果等信息

  • AX
  • BX
  • CX
  • DX

    3.3.2. 指针寄存器

  • SP 堆栈指针

指示栈顶的偏移地址,不能再用于其他目的

  • BP 基址指针

表示数据在堆栈段中某个单元的偏移地址

3.3.3. 变址寄存器

常用于存储器寻址时提供地址

  • SI 源地址
  • DI 目的地址

串操作类指令中,SI 和 DI具有特别的功能

3.3.4. 段寄存器

每个段寄存器用来确定一个逻辑段的起始地址,CPU访问内存时由段寄存器提供内存单元的段地址

  • CS 代码段

CS寄存器不允许用MOV指令赋值

任意时刻CPU将CS:IP指向的内容作为指令执行,CPU复位后执行的第一条指令位于CS=FFFFH,IP=0000H

从CS:IP指向的内存单元读取指令,存入指令缓冲器

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

CPU执行指令缓冲器中的指令

  • DS 数据段

通常存放要访问的数据的段地址

  • SS 堆栈段

任意时刻SS:SP指向栈顶元素,SS存放栈顶的段地址,SP存放栈顶的偏移地址

栈为空时,SS:SP指向栈最底部单元下面的字单元

SP是16位寄存器,栈的深度是64KB,最多可放32K个字的数据

  • ES 附加段

处理器利用ES:EA(有效地址)存取附加段中的数据 v串操作指令将附加段作为其目的操作数的存放区域

3.3.5. 控制寄存器

  • IP 指令指针

指示代码段中下一条指令的偏移地址

与代码段寄存器 CS 联用(CS:IP),确定下一条指令的物理地址

  • FLAGS 标志寄存器

用于反映指令执行结果或控制指令执行形式

共9 个标志,分为6个条件标志码标志和3个控制标志

  • 条件码标志

CF 进位标志,结果最高位向前进位时(无符号数才考虑进位)

SF 符号标志,结果最高位(符号位)为负时

ZF 零标志,结果为0

OF 溢出标志

AF 辅助进位标志,结果中第3位(半字节)向前进位时

PF 奇偶标志,结果中1的个数为偶数个时

  • 控制标志

DF 方向标志

IF 中断标志

TF 陷阱标志

3.3.6. 注意

  • 进位标志表示无符号数运算结果是否超出范围,运算结果仍然正确
  • 溢出标志表示有符号数运算结果是否超出范围,运算结果不正确
例1:3AH + 7CH=B6H  
即00111010 + 01111100 = 10110110
无符号数运算:	58+124=182
	范围内,无进位
有符号数运算: 	58+124=182
	范围外,有溢出

3.4. 内存储器

3.4.1. 内存地址

cpu对内存的访问,通过地址总线,地址总线的每一组二进制数对应一个存储单元。

当地址总线只有1根时,只有0、1两个状态,所以对应2个存储单元。当地址总线有2根时,只有00、01、10、11四个状态,所以对应4个存储单元。

地址位数与存储空间关系

若地址位数为 n,则CPU可以直接寻址 2^n个存储单元

3.4.2. 存储单元

在8086中一个实际的存储单元只存放8位二进制数,称为字节单元,存储单元从0开始顺序编号

注意:为方便人阅读,内存和寄存器中数据用十六进制表示

3.4.3. 物理地址

  • 内存单元的真实地址
  • 存储单元的物理地址是唯一的
  • CPU直接读取的地址
  • 8086CPU有20根地址线,cpu可直接寻址的存储单元可达 2^20 个,每个存储单元的地址应该用20位二进制数表示,用十六进制表示的范围是 [00000H,FFFFFH]

3.4.4. 逻辑地址

  • 不唯一
  • 形式:段地址 : 偏移地址

段地址(SA)

段地址指逻辑段在主存中的起始位置,必须是分段后的小段的首地址

偏移地址(EA、有效地址)

偏移地址用来定位段中的内存单元

3.4.5. 逻辑地址和物理地址的转换

  • 由CPU的地址加法器实现
  • 段地址 x 16 定位段的起始地址(基础地址)

所以段的起始地址一定是16的倍数

  • 物理地址 = 基础地址 + 偏移地址

也就是将十六进制的段地址左移1位,再加十六进制的偏移地址

3.4.6. 字的传送

因为一个存储单元只存放8位二进制数,即一个字节。只要在mov指令中给出16位的寄存器就可以进行16位数据的传送了

MOV BX,1000H
MOV DS,BX

MOV AX,[0]  表示将起始内存为1000:0000的字数据存放到AX中
MOV AL,[0]  表示将起始内存为1000:0000的字节数据存放到AL中

当要存放较大的数据时,使用高高低低的方式存放。即低字节存入低地址,高字节存入高地址。表达时,用它的低地址表示多字节数据占据的地址空间。

图中

字单元的内容为

[00002H] = 1256H

双字单元的内容为

[00002H] = 67341256H

3.4.7. 数据的地址对齐

  • 同一个存储器地址可以是字节单元地址、字单元地址、双字单元地址等等。
  • 字单元安排在偶地址(xxx0B)、双字单元安排在模4地址(xx00B)等,被称为”地址对齐“

    3.4.8. 计算某数据区最末单元的物理地址

末单元物理地址=首地址+(N-1)*TYPE

N为存储区空间大小,单位是字节,因为地址是从0开始,所以要减一

TYPE 是存储区的数据类型所占存储单元个数,如字节型,值为1,字型为2

3.4.9. 存储单元中地址与内容

地址与内容的区分方法是:用括号将地址括起来以代表单元的内容

(3075A H) = 12 H 代表3075A H单元中的内容是 12H

(37692 H) = 5678 H 代表37692 H单元和 37693 H单元一起存放 5678H,该单元是字单元

3.4.10. 存储器分段

解决16位字长的机器提供20位地址的问题,段的划分来源于CPU,内存并没有分段

概念

8086CPU将1MB空间分成许多逻辑段

大段:每个段最大限制为64KB(偏移地址是16位的2进制数,所以2^16=64KB),最大可有16个段

小段:每16个字节为一小段,共有64K个(65536)小段

段内单元的地址用16位二进制数表示,称为偏移地址

每小段第一个单元的物理地址称小段首地址

小段首地址的特点是低位为 0H

省略最低位 0H,就可用16位段寄存器保存小段首地址

各个段之间可以重叠

类型

  • 代码段
  • 数据段
  • 附加段
  • 堆栈段

注意:在汇编程序中,必须有代码段

4. 第三章

汇编语言有3种指令

  • 汇编指令

机器码的助记符,有对应的机器码

  • 伪指令

没有对应的机器码,由编译器执行,计算机不执行

  • 宏指令

不同机器对应不同的指令系统

4.1. 汇编指令

4.1.1. 格式

操作码字段 操作数字段

操作数用来指明被操作的数的值或数据的存放位置

只有操作码,没有操作数,称为零地址指令

4.1.2. 属性

指令长度

以字节为单位

执行时间

以CPU时钟周期为单位

4.1.3. 注意

  • 符号地址代表位移量
  • [...]代表一个内存单元,[32H]表示偏移地址是32H,[]表示的单元长度可由具体指令中的其他操作对象指出

4.2. 内存单元的描述

  • 内存单元的地址

[0]表示单元的偏移地址为0

  • 内存单元的长度(类型)

MOV AX,0002H

MOV AL,02H

4.3. 指令的寻址

指令的寻址方式有两大类:与数据有关的寻址和与转移地址有关的寻址

寻址方式:指的是指令按什么方式给出操作数或与其有关的地址信息

4.3.1. 段前缀(段超越)

与内存有关的寻址中,操作数的段地址默认为数据段,段地址除了在数据段中,还可以在其他三种段中,若放在其他三段中,则称为段超越。

MOV AX,DS:[2000H]

4.4. 数据相关寻址

对数据操作数而言,数据可能在内存中、CPU的寄存器中、或直接写在指令中。若数据不在内存中存放,操作数就没有逻辑地址的概念

4.4.1. 立即寻址

操作数直接包含在指令中,紧跟在操作码之后的寻址方式称为立即寻址方式,把该操作数称为立即数

注意:立即寻址方式只能出现在源操作数的位置

MOV AL,[32H]
MOV AX,1234H
MOV BX,16
MOV EAX,56H

4.4.2. 寄存器寻址

操作数直接包含在寄存器中,由指令指定寄存器

注意:寄存器可以是8位、16位、32位通用寄存器或16位段寄存器,但CS不能用于目标

MOV AX,BX

4.4.3. 存储器寻址

直接寻址

MOV AX,DS:[2000H]
操作数的有效地址EA直接写在指令中,用括号里的数值作为操作数的偏移地址(有效地址),操作数的段地址为数据段,由DS指出
注意:不加DS:前缀,汇编时会认为,[2000H]是立即数而不是偏移地址

直接寻址还可以有符号地址(代表位移量),即为存储单元定义一个变量名

x dw 5678H
MOV AX,X
或
MOV AX,[X]

寄存器间接寻址

有效地址存放在BX,BP或SI、DI中

默认段地址在DS,可使用段超越前缀改变

若使用的是BP,则段地址是SS

MOV AX,[BX]
MOV AX,SS:[BP]  这里使用了段超越前缀

寄存器相对寻址

操作数的有效地址是一个基址或变址寄存器的内容再加上8位或16位位移量之和

MOV AX,[BX+1234H]
MOV AX,VALUE[BX] #符号地址

基址变址寻址

操作数的有效地址是一个基存储器和一个变址寄存器的内容之和。该方法可用于二维表的处理

MOV AX,[BX+DI]
MOV AX,[BX][DI]

相对基址变址寻址

操作数的有效地址是一个基存储器加一个变址寄存器再加一个位移量。该方法可用于二维查表和栈处理

MOV AX,[MASK+BX+SI]

注意:以上寻址方式得到的地址只是有效地址(偏移地址)简写为EA,段基址与段寄存器有关

  • 对双操作数指令而言,两个操作数不允许同时用存储器寻址方式

4.5. 栈

4.5.1. 指令

入栈和出栈操作以字单位进行操作

  • pop(出栈)

先读取SS:SP处的数据,再改变SP

SP = SP + 2

  • push(入栈)

先改变SP,再向SS:SP传送地址

SP = SP + 2

4.5.2. 操作

  • 任意时刻SS:SP指向栈顶元素,SS存放栈顶的段地址,SP存放栈顶的偏移地址
  • 栈为空时,SS:SP指向栈最底部单元下面的字单元(字单元的低字节的地址)
  • SP是16位寄存器,栈的深度是64KB,最多可放32K个字的数据

4.5.3. 计算sp

因为栈的操作单位是字,若定义一个段的范围是10000H~1000FH

  • 栈中只有一个元素时,SP应该指向1000EH,即为栈的最后一个字单元的低地址
  • 栈空时,SP应该指向100010H,即为栈的最后一个字单元后面的一个字单元的低地址

4.5.4. 用途

源程序需要暂存数据的时候,一般存在栈中

;以1000CH-1000FH段内存为栈
MOV AX,1000H
MOV SS,AX
MOV SP,0010H

MOV AX,001AH	;以字为单位进行操作
MVO BX,001BH

PUSH AX
PUSH BX

5. Debug使用

5.1. debug特性

  • debug 默认是十六进制
  • 不区分大小写

5.2. 常用指令

5.2.1. R - 查改寄存器内容

查看、改变CPU寄存器的内容

  • R 寄存器名

修改寄存器的内容

5.2.2. D - 显示内存单元

查看内存中的内容

  • D 段地址:偏移地址

查看指定内存处的内容

左边是每行的起始地址

中间是从指定地址开始的128个内存单元的内容,以16进制的形式显示,每行的起始地址都是16的整数倍,每行最多输出16个单元的内容

右边是每个内存单元中的数据对应的可显示的ASCII码

  • D 段地址:起始偏移地址 结尾偏移地址

查看一段内存中的内容

5.2.3. E - 修改内存单元

改写内存中的内容

  • E 段地址:起始偏移地址 数据 数据 数据 数据...

一起修改内存单元的数据

  • E 段地址:起始偏移地址

一个一个的修改内存单元的数据

输入E 段地址:起始偏移地址后,按Enter键,显示起始地址和第一单元的原始内容,光标停在.后,在.后输入要修改的数据,然后按空格键

  • 内存中写入字符

写入字符时,要加单引号

5.2.4. U - 反汇编

将内存中的机器指令翻译为汇编指令

  • U 段地址:偏移地址
  • U 段地址:起始偏移地址 结尾偏移地址

从内存1000:0000处开始写入一段机器码

B80100 对应 MOV AX,0001

B90200 对应 MOV CX,0002

01C8 对应 ADD AX,CX

5.2.5. T - 跟踪

执行一条或多条机器指令,默认执行CS:IP指向的命令

  • T =段地址:偏移地址

  • T =段地址:偏移地址 指令条数

5.2.6. A - 汇编

以汇编指令的格式在内存中写入一条机器指令

5.2.7. P - 执行过程

执行一条指令或一个完整的子程序

与T指令类似,当遇到下一条指令是INT 21的时候,要使用P指令来执行命令

5.2.8. Q - 退出

5.3. 熟悉界面

  • 右边显示数据的ASCII码对应的字符
  • 中间显示存储的数据
  • 左边显示

6. 第四章

6.1. 汇编程序

ASSUME CS:CODES
CODES SEGMENT 
START:
    MOV AX,3
    MOV BX,5
    ADD BX,AX
    INT 21H
CODES ENDS
END START

6.1.1. 概念

  • 源程序

汇编文件中的所有内容

  • 程序

最终由计算机执行的程序

6.1.2. 形成

编辑.asm文件 编译生成.obj 连接生成.exe文件

6.1.3. 伪指令

  • segmentends

定义一个段

段名 segment
...
...
...
段名 ends
  • end

一个汇编程序的结束标记

end 标号通知编译器程序的入口,end 标号会被转化为一个入口地址

下面源程序中end指明了程序的入口在标号start处

ASSUME CS:CODES
	CODES SEGMENT 
START:
    MOV AX,3
    MOV BX,5
    ADD BX,AX
    INT 21H
CODES ENDS
    END START
  • assume

将有特定用途的段和相关的段寄存器关联起来

将用作代码段的段codesg和寄存器cs关联起来
assume  cs:codesg

6.1.4. 标号

一个标号代表一个地址

codesg segment
codesg最终将被处理为一个段的段地址

6.1.5. 程序返回

程序P2若要运行,则需要有一个正在运行的P1程序将P2程序加载,然后将CPU的控制权交给P2,P2执行结束后将权限再交给P1,这个过程叫程序返回

MOV AX,4c00H
int 21H
这两段代码的功能就是程序返回

6.1.6. EXE的加载

  • 程序加载后,ds中存放着程序所在内存区的段地址,这个内存区的偏移地址为0
  • 这个内存区的前256个字节(100H)中存放的是PSP,DOS用来和程序进行通信,256个字节后的空间是存放程序的
  • PSP的段地址SA
  • 程序存放的物理地址
SA x 16 + 0 + 256 = SA x 16 + 16 x 16 
或
SA + 10H : 0

6.2. 注意

汇编源程序中,数据不能以字母开头

ffff H 需要写为 0ffff H

7. 第五章

7.1. LOOP

assume cs:codesg
codesg segment
	MOV AX,2
	MOV CX,3
S:	ADD AX,AX	;标号S标记了一个地址,这个地址有一条指令	ADD AX,AX
	LOOP S	
	
	MOV AX,4c00H
	INT 21H
codesg ends
end

7.1.1. 格式

loop 标号

7.1.2. 操作

  • CX中的内容减1
  • 判断CX中的值,不为0则转至标号处继续执行,若为0则向下执行

7.1.3. 使用

  • 通常用CX存放循环次数
  • 要使用一个标号,指示循环体的起始地址
  • 循环体应位于标号和loop指令间
  • 当遇到loop时,可使用P指令执行,会自动执行完循环

7.1.4. 寻址范围

通常段内寻址的范围是[-128,127]

loop指令是不允许往后面跳的,所以后127的范围是不生效的,它构成的循环范围是在-128字节之内

7.2. 安全空间

  • DOS下,0:200~0:2ff空间是安全空间
  • 向内存中写内容时,可以写在安全空间中

    7.3. 其他

  • idata

约定符号idata表示常量

  • inc bx

将BX中的内容加1

  • dec bx

将BX中的内容减1

8. 第六章

程序取得所需空间的方法

  • 在加载程序的过程中为程序分配
  • 程序在执行的过程中向系统申请

8.1. 代码段中使用数据

ASSUME CS:CODE
CODE SEGMENT
	DW 0123H,0456H,0789H,0ABCH,0DEFH,0FEDH,0CBAH,0987H
	
	MOV AX,0
	MOV BX,0
	
	MOV CX,8
	
S:	ADD AX,CS:[BX]
	ADD BX,2
	LOOP S
	
	MOV AX,4C00H
	INT 21H
CODE ENDS

END

8.1.1. db

  • define byte,定义字节型数据

    8.1.2. dw

  • define word,定义字型数据
  • 可以通过定义一些值为0的字数据来开辟一段内存空间

  • 在代码段中的最开始部分定义数据,所以第一个数据的偏移地址是0,而段地址就是存放在寄存器CS中的代码段的地址
ASSUME CS:CODES
CODES SEGMENT 
;定义数据
START:
;代码
    ADD BX,AX
    INT 21H
CODES ENDS
END START

8.2. 多个段的程序

ASSUME CS:CODES,DS:DATA,SS:STACK
DATA SEGMENT
	DW 0123H
DATA ENDS

STACK SEGMENT
	DW 0,0,0,0,0
STACK ENDS

CODES SEGMENT 
START:
	MOV AX,STACK
	MOV SS,AX
	
	MOV AX,DATA
	MOV DS,AX
	
    INT 21H
CODES ENDS
END START

8.2.1. 对段地址的引用

段名就相当于一个标号,它代表了段地址,如MOV AX,STACK表示将名称为STACK的段的段地址送入AX

8.2.2. 多个段的关系

在源程序中定义的多个段,在内存中是连续的,按源程序中的顺序在内存中排列,知道其中一个段的段地址就可以知道其他段的段地址

9. 第七章

9.1. and

将操作对象的指定位设置为0,其他位不变

OR AL,00100000B

9.2. or

将操作对象的指定位设置为1,其他位不变

OR AL,00100000B

9.3. 字符型数据

字符型数据以''的形式给出,编译器将它们转为ASCII码,用DB定义

9.4. 大小写转换

以ASCII码的二进制来看,大小写字母只有第5位不一样,大写字母第5位为0,小写字母第5位为1

使用or、and可转换大小写

全部转为小写字母
ASSUME CS:CODES,DS:DATAS
DATAS SEGMENT
	db 'BaSiC'
DATAS ENDS

CODES SEGMENT
    
START:
    MOV AX,DATAS
    MOV DS,AX
    
    MOV BX,0
    MOV CX,5
S:	MOV AL,[BX]
	OR AL,00100000B
	MOV [BX],AL
	INC BX
	LOOP S
	 
    
    MOV AH,4C00H
    INT 21H
CODES ENDS
END START

9.5. 定位内存地址

9.5.1. [bx + idata]

常见格式

  • mov ax,[200 + bx]
  • mov ax,200[bx]
  • mov ax,[bx].200

处理数组

当要操作的数据,起始偏移地址不同,但是从起始偏移地址开始的相对地址变化相同时,可以看做是两个长度一样的数组

C语言 a[i]、b[i]

汇编 idata1[bx]、idata2[bx]

将数据段中定义的第一个字符串转为大写,第二个字符串转为小写
ASSUME CS:CODES,DS:DATA
DATA SEGMENT
	DB 'BaSiC'
	DB 'MinIX'
DATA ENDS

CODES SEGMENT
START:
	MOV AX,DATA
	MOV DS,AX
	
	MOV BX,0
	MOV CX,5
S:	MOV AL,0[BX]
	AND AL,11011111B
	MOV 0[BX],AL
	
	MOV AL,5[BX]
	OR AL,00100000B
	MOV 5[BX],AL
	INC BX
	LOOP S
	
	MOV AX,4C00H
	INT 21H
CODES ENDS
END START

9.5.2. [bx + si][bx + di]

常用格式

  • mov ax,[bx][si]

9.5.3. [bx + si + idata][bx + di + idata]

常用格式

  • mov ax,[bx + 200 + si]
  • mov ax,[200 + bx + si]
  • mov ax,200[bx][si]
  • mov ax,[bx].200[si]
  • mov ax,[bx][si].200

9.5.4. 二重循环

10. 第八章

reg表示一个寄存器

sreg表示一个段寄存器

10.1. [...]表示的内存地址

[]表示的单元长度可由具体指令中的其他操作对象指出

10.1.1. bx、si、di、bp

只有bx、si、di、bp可以用在[]中来进行内存单元的寻址

10.1.2. 组合

  • bx、si、di、bp 寄存器单个出现
  • bx和si/di
  • bp和si/di

10.1.3. bp

只要在[]中使用寄存器bp,且没有显性的给出段地址,段地址就默认在SS中

10.2. 指令中数据的长度

在指令中要指明,指令操作的是字型数据还是字节型数据

10.2.1. ptr

在没有寄存器名的情况下使用操作符 X ptr指明内存单元的长度,X的值为word或byte

word ptr指明访问的内存单元是字型
inc word ptr [bx]

byte ptr指明访问的内存单元是字节型
inc byte ptr [bx]

10.3. div

除法指令

  • 格式

div 寄存器div 内存单元

div byte ptr ds:[21]
  • 除数

有8位和16位两种,在一个寄存器中或内存单元中

  • 被除数

默认放在AX或AX和DX中

如果除数为8位,被除数为16位,则默认放在AX中

如果除数为16位,被除数为32位,则放在DX和AX中,DX存放高16位,AX存放低16位

  • 结果

如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数

如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数

10.4. dd

double word,定义双字型的数据

10.5. dup

用来定义重复数据,和db、dw、dd配合使用

db 3 dup (0) 相当于 db 0,0,0
db 3 dup (0,1,2) 相当于 db 0,1,2,0,1,2,0,1,2

11. 第九章

11.1. 转移行为

11.1.1. 段内转移

只修改IP

短转移

IP修改范围 -128~127(补码表示)

近转移

IP修改范围 -32768~32767(补码表示)

11.1.2. 段间转移

同时修改CS和IP

11.2. 操作符offset

由编译器处理,获取标号的偏移地址

assume cs:code
code segment
	start:
	mov ax,offset start		;相当于 mov ax,0
	s:
	mov ax,offset s			;相当于 mov ax,3
code ends
end start

11.3. 转移指令

11.3.1. 注

一般的汇编指令中,指令中的idata(立即数),都会在机器指令中出现

11.3.2. 转移原理

位移转移

  • jmp short 标号

段内短转移,转到标号处执行指令

(IP) = (IP) + 8位位移

8位位移 = 标号处的地址 - jmp指令后的第一个字节的地址

  • jmp near ptr 标号

段内近转移,转到标号处执行指令

(IP) = (IP) +16位位移

16位位移 = 标号处的地址 - jmp指令后的第一个字节的地址

目的地址转移

  • jmp far ptr 标号

段间转移

(CS) = 标号所在段的段地址

(IP) = 标号在段中的偏移地址

地址在寄存器中

  • jmp 16位reg

(IP) = (16位reg)

地址在内存中

  • jmp word ptr 内存单元地址

段内转移

从内存单元地址处开始存放一个字,是转移的目的偏移地址

mov ax,0123H
mov ds:[0],ax
jmp word ptr ds:[0]		;(IP) = 0123H
  • jmp dword ptr 内存单元地址

段间转移

从内存单元地址处开始存放两个字

(CS) = (内存单元地址 + 2)

(IP) = (内存单元地址)

mov ax,0123H
mov ds:[0],ax
mov word ptr ds:[2],0
jmp dword ptr ds:[0]

(CS) = 0
(IP) = 0123H

11.3.3. 条件转移

所有条件转移都是短转移,转移位移的范围[-128,127]

  • jcxz 标号(OPR)

如果(cx) = 0,转移到标号处

(IP) = (IP) + 8位位移

8位位移 = 标号处的地址 - jcxz指令后的第一个字节的地址

11.3.4. loop指令

所有循环指令都是短转移

如果(cx) != 0,就转移到标号处

(IP) = (IP) + 8位位移

8位位移 = 标号处的地址 - loop指令后的第一个字节的地址

11.3.5. 总结

根据位移转移,因为是靠位移来实现在段内进行转移,所以能保证程序在内存的不同位置都能正常执行

12. 第十章

12.1. ret

利用栈中数据修改IP的内容,实现近转移

执行ret指令,相当于

pop IP

12.2. retf

利用栈中数据修改CS、IP内容,实现远转移

执行retf指令,相当于

pop IP 
pop CS

12.3. call

将当前的IP或CS和IP压入栈中

转移

12.3.1. 位移转移

将当前的IP压栈后,转到标号处执行指令

段内直接调用

CALL 标号

相当于
push IP
jmp near ptr 标号

12.3.2. 目的地址转移

段间直接远调用

CALL far ptr 标号

相当于
push CS
push IP
jmp far ptr 标号

12.3.3. 转移地址在寄存器中

段内间接调用

CALL 16位reg

相当于
push IP
jmp 16位reg

12.3.4. 转移地址在内存中

段内间接调用

CALL WORD PTR 内存单元地址

相当于
push IP
jmp word ptr 内存单元地址

段间间接调用

CALL DWORD PTR 内存单元地址

相当于
push CS
push IP
jmp dword ptr 内存单元地址

13. 第十一章

13.1. 标志寄存器

13.1.1. 规律

  • 大多数运算指令都影响标志位

add、sub、mul、div、inc、or、and等

  • 大多数传送指令都不影响标志位

mov、push、pop

13.1.2. flag寄存器

按位起作用(共16位)

0、2、4、6、7、8、9、10、11位都有特殊含义

13.1.3. 标志

标志寄存器中的某个标志,值为1表示有某种状态,为0表示无某种状态

标志 说明
ZF 记录指令执行后,其结果是否为0
PF 记录指令执行后,其结果所有bit位中1的个数是否为偶数
SF 记录指令执行后,其结果是否为负
CF 进行无符号数计算时,记录其结果的最高有效位向更高位的进位值或从更高位的借位值
OF 有符号数运算后,其结果是否产生溢出
DF 串操作指令中,控制每次操作后SI、DI的增减

14. 分支程序

分支程序要统一入口,出口

14.1. 位操作的分支程序

如 test指令

14.2. 菜单法

14.2.1. 原理

主要利用比较指令判断输入的菜单号,然后利用条件转移指令跳转到指定程序执行

14.2.2. 缺点

菜单项较多时,需要使用较多的比较指令和条件转移指令,程序冗长

         mov al,x
	       CMP	Al,0	  ;与0进行比较
	       JGE	A1	       ;X≥0转A1
	       MOV	Y,-1	  ;X <0时,-1→Y
	       JMP	EXIT
A1:     JG	A2 	       	   ;X>0转
	       MOV	Y,0	       ;X=0时,0→Y
	       JMP	EXIT
A2:     MOV	Y,1	       	  ;X>0,1→Y 

EXIT:   MOV	AH,4CH
	       INT	21H 

14.3. 跳转表法

跳转表法,表中顺序存放着进入各分支处理程序的程序段名(标号)或转移指令,称它们为跳转表的元素


  1.跳转表中存放多分支程序的偏移地址(标号)
  2.跳转表中存放多分支程序的转移指令

DATAS SEGMENT
    BASE   DW SUB1,SUB2,SUB3,SUB4,SUB5,……
    BN     DB 3   
DATAS ENDS

CODES SEGMENT
start:

      MOV AL, BN      
      MOV AH, 0
      DEC AL          ;建索引号
      SHL AL, 1       ; (3-1)*2
      MOV BX, OFFSET  BASE  ;?不用XLAT?
      ADD BX, AX      ;求功能3的有效地址 
      MOV BX, [BX];      jmp near ptr  [bx]
      JMP BX       ;BX中存放具体标号(SUB3)


SUB1: ....
      JMP EXIT
      .....
SUB2: ....
      JMP EXIT
      .....
SUB3: .......
      JMP EXIT
      .....
      .....
SUB8: .....
      JMP EXIT
EXIT:

CODES ENDS


15. 循环程序

找出循环体最后结果的输出点

15.1. 先判断,后执行

CMP

15.2. 先执行,后判断

LOOP

16. 串操作

16.1. 概念

连续n 个存储单元称为串、表、数组等

16.2. 处理

  • 串操作指令把附加段作为目的操作数的存放区域

可以定义一个附加段,也可以把数据段、附加段定义为同一个段

17. 多重循环

用两条loop指令实现双重循环时,对CX有冲突,可以用push CX,将外循环的CX进栈保存,内循环的LOOP结束后,再将外循环的CX恢复

17.1. 常用循环控制方法

  • 计数器控制法:循环次数已知
  • 条件控制法:循环次数未知
  • 逻辑尺控制法:将标志位放入存储单元,存储单元就称为逻辑尺

17.2. 内外循环的控制

不允许内外循环交叉

17.3. 内外循环的跳转

只允许从内向外跳,不允许从外向内跳

用冒泡排序,实现升序排列

ASSUME CS:CODES,DS:DATAS,SS:STACKS

DATAS SEGMENT
   buf DW 12,32,45,1,33       ;要排序的数
   COUNT DW ?      ;数组元素个数
DATAS ENDS

STACKS SEGMENT
    ;此处输入堆栈段代码
STACKS ENDS

CODES SEGMENT

START:

	MOV AX,DATAS
	MOV DS,AX
    
	;此段代码,按冒泡排序,小到大
	MOV CX,COUNT	#count 记录数组长度
	DEC CX		;记录循环次数
	
lp1:			;外循环
	PUSH CX		;记录外循环次数
	MOV BX,0
					
lp2:    		;内循环
	MOV AX,buf[BX]
	CMP AX,buf[BX+2]	;比较大小
	JLE next
	XCHG AX,buf[BX+2]
	MOV buf[BX],AX
	
next:	
	ADD BX,2
	LOOP lp2
	POP CX		;恢复外循环次数
	LOOP lp1

finish:	
	MOV AH,4CH
	INT 21H

CODES ENDS
END START

18. 子程序

18.1. 概念

一个具有一定功能的程序段,子程序又叫过程

18.2. 定义子程序

18.2.1. 方法一

将子程序第一条指令的标号作为子程序名调用(使用call调用)

18.2.2. 方法二

伪指令proc

格式

子程序名 proc 属性       
...
...
...
子程序名 endp

注:属性为 near或far

属性的确定原则:
1.主程序和子程序在同一个代码段内,用near
2.主程序和子程序不在同一个代码段内,用far
3.主程序是第一个被执行的程序,则主程序应定义为far(相对DOS系统来讲)

18.3. call执行子程序

用call指令转去执行子程序,跳转之前call指令后面的指令的地址将存储在栈中

18.4. 现场保护

为防止主程序中用寄存器存的数据被子程序覆盖,将主程序中用到的所有寄存器中的内容存入栈中,在子程序返回前再恢复

18.5. 参数和结果的传递

如何将值传递给子程序去执行,然后将结果返回到主程序

18.5.1. 方法一

将数据存入内存中,然后传递其所在内存空间的首地址

18.5.2. 方法二

使用栈

19. 嵌套与递归

19.1. 子程序嵌套

19.2. 子程序递归

20. 宏汇编

20.1. 概念

宏是源程序中具有一段独立功能的程序代码

20.2. 宏使用

20.2.1. 宏定义

一对伪指令MACRO、ENDM

格式

宏名字 MACRO 哑元1,哑元2,哑元3...
	语句串
	ENDM
说明:
语句串代表宏定义体,即具体的程序代码
哑元代表形参,用逗号分割,可以没有形参,和哑元对应的是实元,相当于实参(实元和哑元统称为变元)

例
两数相加宏指令
SUMM MACRO x1,x2,x3
	MOV AX,x1
	ADD AX,x2
	MOV X3,AX
	ENDM

20.2.2. 宏调用

使用宏时,直接写出宏的名称即可,若有参数,后面跟上参数

例
调用宏SUMM实现(BX) = 34 + 25
SUMM 34,25,BX

20.2.3. 宏展开

源程序在汇编时,宏指令会被汇编程序用相应的代码替换(用宏定义体替换)

20.3. 宏参数

20.3.1. 变元是操作数

TEST MACRO x1,x2
	MOV AX,x1
	ADD AX,x2
ENDM

20.3.2. 变元是操作码

TEST MACRO x1,x2
	x1 AX,2
	x2 AX,3
ENDM

20.3.3. 变元是操作码的一部分

&作为分隔符,变元替换掉&后面的字符

TEST MACRO x1,x2
	MO&x1 AX,2
	AD&x2 AX,3
ENDM
宏调用
TEST V,D 
等价于
	MOV AX,2
	ADD AX,3

20.3.4. 变元是存储单元

TEST MACRO x1,x2,x3
	x1 DB x2 DUP(x3)
ENDM

宏调用
TEST SS,6,5
等价于
SS DB 6 DUP(5)

20.3.5. 变元是字符串

TEST MACRO x1
	SS DB 'Number &x1','$'
ENDM

宏调用
TEST abc
等价于
SS DB 'Number abc','$'

20.4. 宏运算

5种

  • &

替换运算

  • <>

传递运算

如果实元是含有空格的字符串,则实元要用<>括起来

  • !

转义运算

当字符串中含有<>时,为防止与传递运算符冲突,用!>!<来转义

  • %

表达式运算

如果实元中有表达式,%将表达式的值作为实元

TEST % 35+12

  • ;;

宏注释

20.5. 宏和子程序

20.5.1. 区别

  • 子程序是能够实现一定功能的代码,使用方法只能是跳转到子程序所在位置去执行,不能传参数
  • 宏类似高级语言的自定义函数,可以传参数

20.5.2. 优缺点

  • 当传递参数较多时,可优先考虑宏
  • 宏使用过多,会导致主程序代码太长,占用内存空间过大
  • 当程序较长或对内存空间有要求时,可优先考虑子程序

21. 中断

21.1. 外中断

硬中断

21.2. 内中断

软中断

22. 查询手册

22.1. 如何学习指令

  • 操作数是单还是双
  • 操作数的类型要求(有符号、无符号、一个地址、立即数…)
  • 指令执行了哪些操作
  • 是否影响标志位
  • 结果是否回送

22.2. 指令分类

  • 汇编指令(计算机执行)
  • 伪指令(编译器执行)
  • 宏指令

22.3. 伪指令

22.3.1. 定义段

段名 segment 
...
...
段名 ends

22.3.2. ASSUME

assume 段寄存器:段名

22.3.3. 数据定义

(变量名)存储单元名 DB 操作数

DB 个数 dup(?)  ;重复定义相同操作数

注意:
一条数据定义指令,可为多个存储单元赋值
操作数默认是10进制的,定义16进制后面加H
数字不能以字母开头,前面要加0
操作数可为 ? 表示为变量预留空间而不赋初值
操作数可为表达式,表达式会先计算,再将结果存到存储单元
操作数若为字符串,要用单引号包围
字符串应使用DB定义,存入的是字符串的ASCII码

22.3.4. 赋值伪指令

变量名 EQU 表达式或数据 

变量名 = 表达书或数据

注意:
EQU不允许重复定义,即一个变量名只能使用一次
= 允许重复定义

如
CR EQU 0DH  
MOV	AL,CR  ;等价于 MOV  AL, 0DH

22.3.5. 模块定义伪指令

name 模块名
...
...
end 起始标号

注意:
name伪指令可缺省

22.3.6. $地址计数器

$ 表示当前的偏移地址

如:jmp $+5 则跳转到当前指令的偏移地址加5的单元

22.3.7. ORG设置当前偏移地址

在数据段中,可以在指定偏移地址的存储单元存放数据
在代码段中,可以从指定单元开始存放并执行指令

如 org 0020H 表示设置当前偏移地址为 0020H

22.3.8. 操作符

程序在汇编时,将这些操作符变为相应的数值回送或者定义属性

offset(回送偏移地址)

mov bx,offset x	;将x单元的偏移地址送给bx
mov ax,offset start	;将标号start的偏移地址送给 ax

seg(回送段地址)

mov bx,seg x	;将x单元的段地址送给bx

type(类型回送)

mov bx,type x ;

注意:
如果 x 是字节单元,回送值为 1 
如果 x 是字单元,回送值为 2 

length(变量数回送)

mov cx,length y

注意
y如果是dup()定义的,cx = 变量的个数

size(字节数回送)

mov ax,size y

注意:
如果y是用dup()定义的,ax = 所有变量所占的总字节数

ptr(属性定义)

mov byte ptr [bx],10	;定义目的操作数为字节单元
mov word ptr [ax],20	;定义目的操作数为字单元

this(多重属性操作)

要与EQU配合

label(类型操作符)

x label byte ;将x单元的类型定义为byte字节型

22.3.9. 注释伪指令

;

22.4. 基本汇编指令

操作数的属性必须一致

22.4.1. 数据、栈及查表

数据操作指令不影响标志位

mov(传送指令)

注意:
立即数是字节型还是字型
明确指令是字节操作还是字操作
目标寄存器不能是CS
立即数和存储器数不能直接送段寄存器
两个段寄存器间不能直接传送
两个存储单元之间不能直接传送

xchg(数据交换)

xchg ax,bx ;交换bx和ax的内容

注意:
必须有一个操作数是寄存器
操作数不能是立即数

push(进栈)

注意:
操作单位是 字

pop(出栈)

注意:
操作单位是 字
PUSH  SP指令入栈的是该指令已修改的SP新值,
PUSH  ESP指令入栈的是执行该指令之前的ESP旧值,
POP ESP使用指令执行后的ESP内容.

xlat(查表转换指令)

通过AL寄存器中的索引值在表中查得表项内容并返回到AL中

使用这条指令之前,数据段中应有一个字节型表,该表起始地址的偏移量应放入BX,表索引值(要查找单元的位移量)放入AL

(AL) = ((BX)+(AL))

22.4.2. 逻辑地址的获取

这类指令传送的是操作数的地址,而不是操作数本身

不能使用段寄存器

源操作数不能使用立即数和寄存器寻址方式

lea(有效地址传送)

lea 寄存器,存储单元
把源操作数的有效地址送给指定的寄存器(除段寄存器)

注意:
源操作数必须是存储单元
等价的OFFSET后面只能跟变量,不能是变址(DI、SI)

lds(数据段地址传送)

lds 寄存器,双字存储单元
将双字存储单元的低字节送入寄存器,高字节送入DS段寄存器

les(附加段地址传送)

les 寄存器,双字存储单元
将双字存储单元的低字节送入寄存器,高字节送入ES附加段寄存器

22.4.3. 符号位扩展

不影响条件标志位

cbw(字节拓到字)

将al扩展到ax
逻辑意义就是AL的符号扩展到AH

cwd(字拓到双字)

将ax扩展到dx

22.5. 算术运算指令

任何一条二进制加、减法指令均适用于带符号数和无符号数运算

22.5.1. add(加法)

影响OF、SF、ZF、AF、PF、CF标志

目的操作数是一个存储单元中的数据
对操作数的限定同MOV指令

22.5.2. ADC(进位加法)

影响OF、SF、ZF、AF、PF、CF标志

适用于多字节或多字的加法运算

ADC执行加法运算时,会将CF位的值一起加到目标操作数中
如果必须处理非常大的、不能存放到双字数据长度(ADD可以使用的最大长度)中的整数,可以把值分割为多个双字数据元素,并且对每个元素执行独立的加法操作。
为了正确完成这个操作,必须检测每个加法操作的进位标志,如果进位标志被设置为1,就必须进位到下一对相加的数据元素

22.5.3. inc(加1指令)

除不影响CF标志外,影响其它五个算术运算特征标志

实现地址指针或循环次数的加1修改

22.5.4. 加法指令对条件标志位的影响

sf = 1 结果为负
zf = 1 结果为 0
cf = 1 和的最高有效位,向前进位
cf = 0 
of = 1 两个操作数符号相同,结果符号与之相反
of = 0 

22.5.5. sub(减法)

要求同ADD

22.5.6. sbb(带错位的)

同ADC

22.5.7. dec(减1指令)

和INC功能类似

22.5.8. cmp(比较指令)

可进行两种比较,有符号数比较和无符号数比较

执行相减操作后,根据结果设置标志位,并不改变两个操作数的原值,其它要求同SUB

执行比较指令之后,可以根据标志判断两个数是否相等、大小关系等

22.5.9. neg(求补指令)

对目标操作数(含符号位)求反加1,并且把结果送回目标

利用NEG指令可实现求一个数的相反数

影响OF、SF、ZF、AF、PF、CF标志

22.5.10. 减法指令对条件标志位的影响

cf = 1 的最高有效位,向前进位
cf = 0 
of = 1 
of = 0 

22.6. 混合算术指令

22.6.1. mul(无符号乘法)

实现两个无符号二进制数乘

字节乘法:被乘数放在al中,结果放在ax中
字乘法:被乘数放在ax中,结果放在dx、ax中
乘数写在指令中
注意:
源操作数只能是寄存器(reg)或存储器操作数(m),不能是立即数

对CF和OF的影响是:
若乘积的高半部分(例字节型乘法结果的AH)为0则对CF和OF清0,否则置CF和OF为1

22.6.2. imul(带符号数相乘)

实现两个带符号二进制数乘

规则和mul一样

对CF和OF的影响是:若乘积的高半部分为低半部分的符号扩展,则对CF和OF清0,否则置CF和OF为1

22.6.3. div(无符号除法)

实现两个无符号数除法

格式:

div registre
div 内存单元


注意:

除数

有8位和16位两种,在一个寄存器中或内存单元中

被除数

默认放在AX或AX和DX中

如果除数为8位,被除数为16位,则默认放在AX中

如果除数为16位,被除数为32位,则放在DX和AX中,DX存放高16位,AX存放低16位

结果

如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数

如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数

为了保证被除数位数,需进行位扩展,使用CBW和CWD

22.6.4. idiv(带符号除法)

同div

22.7. 十进制数运算

22.7.1. 压缩的BCD码

只是看起来是用二进制编码表示0~9,在计算时,仍为二进制的计算,所以计算结果需要修正

22.7.1.1. daa(加法调整)

跟在二进制加法指令之后,把AL中的结果调整成压缩BCD码并送回AL

标志:
AF、CF按以上情况设置,SF、ZF、PF按结果设置,OF位不确定

若是多字节加法,可以通过ADC指令把CF的进位加到高位中

22.7.1.2. das(减法调整)

跟在二进制减法指令之后,把AL中的结果调整成两位压缩BCD码并送回AL

22.7.2. 非压缩的BCD码

aaa(加法调整)

跟在二进制减法指令之后
调整AL中的结果成为非压缩BCD码并送回AL
如果AL的低4位大于9,则AL+6,AH+1,AL的高4位清0,CF=1,AF=1

注意:
参与运算的操作数必须是ASCII码或非压缩BCD码

aas(减法调整)

同加法

aam(乘法调整)

跟在乘法指令MUL之后,对AL中的结果进行调整,调整后的非压缩BCD码在AX中。(调整的过程相当于AL除10,商送AH,余数送AL)

aad(除法调整)

除法指令之前,对AX中的非压缩BCD码进行调整,以便执行DIV指令之后,得到非压缩BCD码形式的商在AL中,余数在AH中

22.8. 屏幕显示

直接写显存显示字符

规定偶地址单元放字符的ASCII码,奇地址单元放字符的属性

字符的位置=行号x160D + 列号x2D

22.9. 输入输出

22.9.1. 调用 中断INT 21H

可以通过DOS系统功能调用中断INT 21H,来使用输入、输出

INT 21H 系统功能调用方法

功能号送AH寄存器,
调用参数送所要求的位置,
再执行 INT  21H 系统功能调用中断

22.9.2. 单字符输入

输入的是字符串,但存的是字符串对应的ASCII码

如果输入的是数,运算前,记得减30H

功能号:1
	返回参数:AL=输入字符的ASCII值
	说明:等待从标准输入设备(通常为键盘)输入一个字符,把接收到的字符的ASCII值送给AL,并显示到显示器的当前光标位置。

22.9.3. 单字符输出

存的是ASCII,输出的是字符串

因为存的是字符串对应的ASCII码,所以输出的是数时,记得加30H(之前若减过30H)

功能号:2
	调用参数:DL=字符的ASCII值
	说明:该输出功能使光标跟随移动,同时输出字符的ASCII值送给AL
	例:输出一个字符Y。
		MOV    AH , 2
		MOV    DL , "Y"
		INT      21H

22.9.4. 输出字符串

显示字符串
	功能号:9
	调用参数:DS:DX指向要输出的以$结尾的字符串首地址
	功能:输出字符串到标准输出设备
	说明:要输出的字符串必须以$结束
PRINT	DB 'What is your name$'
MOV	AH,9
MOV DX,OFFSET PRINT
INT	21H

22.9.5. 输入字符串

功能号:0AH
	调用参数:DS:DX指向自定义的输入缓冲区首地址
	功能:从标准输入设备(例如键盘)输入一串字符到用户定义的缓冲区,直到按下Enter键为止,回车符0DH占用一个字节单元,在接收的同时显示到屏幕上,如果超过缓冲区的最大容纳量,则忽略此字符并响铃警告
	说明:定义缓冲区的第一个字节单元为允许输入的最大字符数,第二个字节单元为实际键入的字符个数(系统自动填入),第三个字节单元开始存放键入的字符

BUFFER 	DB 60	;定义缓冲区长度
			DB ?	;存放实际键入的字符数
			DB 61 DUP(?)	;存放实际输入的字符
			;设DS已是BUFFER的段基址
			MOV  AH,0AH	;接收一串字符
			LEA  DX,BUFFER
			INT  21H

22.9.6. 常用输出合集

输出换行

先输出回车符,再输出换行符

方法一

	;实现换行
	MOV AH,2	;先输出 回车符
	MOV DL,0DH
	INT 21H
	
	MOV AH,2	;再输出 换行符
	MOV DL,0AH
	INT 21H

方法二

ASSUME CS:CODES,DS:DATAS

DATAS SEGMENT
	CRLF DB 0AH,0DH,'$'		;存放换行的存储单元
DATAS ENDS

CODES SEGMENT

start:
    MOV AX,DATAS
    MOV DS,AX
    LEA DX, CRLF     ;换行                   
    MOV AH, 09H							 
    INT 21H		

输出输入的字符

输出输入的字符时,记得在输入的字符后面加$再输出

因为输入的字符串最后一个字符是回车符,所以要找到回车符的位置,并将其替换为$

ASSUME CS:CODES,DS:DATAS

DATAS SEGMENT
	n DB 60,?,61 DUP(?)		;存放输入字符串的缓冲区
	
DATAS ENDS

CODES SEGMENT

START:    
		   	
    MOV DX,OFFSET n ;接收字符串,放入缓冲区
    MOV AH,10
    INT 21H
    	
    				;对输入的字符串进行处理,准备输出
    MOV AL,n+1       ;此时AL中存的是实际输入的字符的个数
    ADD AL, 2		;此时AL存的是整个输入缓存区的使用长度,也是回车符所在存储单元的偏移量
    MOV AH, 0		
    MOV SI, AX		;此时 SI 中存的是回车符所在存储单元的偏移量
    MOV n[SI], '$'	;用 $ 替换回车符
    			 
    
	MOV DX,OFFSET n	;已经在输入字符串后面加了 $ ,所以直接 输出输入的字符
    ADD DX,2		
    MOV AH,9							 
    INT 21H

输出数字

在汇编语言中,只能直接输入输出字符串,数字是不能直接输出的,要想把数字输出,就要将其转换成字符串(即字符)的形式,然后再输出数字的字符形式

当数字大于9时,便无法用数字加30H的方式来表示数字的字符形式了。

解决方法:将数字除以10,分别取商和余数组成数的字符形式

如:
12除以10,商为1,余数为2,使用 1、2的字符形式组成12的字符形式

具体实现

;输出数字36

ASSUME CS:CODES,DS:DATAS

DATAS SEGMENT

DATAS ENDS


CODES SEGMENT
   
START:
      MOV AX,DATAS
      MOV DS,AX
      
      MOV AX,36
   	  MOV BL,10
      DIV BL
      
      MOV BL,AH		;BL存放余数
      ADD BL,30H	;余数的ASCII码
	  ADD AL,30H	;商的ASCII码
	  
	  MOV AH,2		;先输出商
	  MOV DL,AL
	  INT 21H
	  
	  MOV AH,2		;再输出余数
	  MOV DL,BL
	  INT 21H


      MOV AX,4C00H
      INT 21H 
  

CODES ENDS
    END START
	

输出多位数

因为2号功能只能输出单个字符,因此如果要输出多位数,需要一位一位的输出,利用将多位数除以10,再用得到的商除10,每次得到的余数,依次为多位数的个位、十位、百位…

在输出未知位数的数字时,需要判断商是否为0,除到商为0,就退出

				;输出3位数,每次除10,取余
	MOV AX,res	 ; res中存的是3位数
	MOV Y,10
	
	DIV Y		;共3位数,求个位
	ADD AH,30H
	MOV g,AH	
	
	CBW			;拓展AL		
	DIV Y		;共2位数,求十位
	ADD AH,30H
	MOV shi,AH
	
	CBW
	DIV Y		;共1位数,求百位
	ADD AH,30H
	MOV bai,AH


	MOV AH,2
	MOV DL,bai
	INT 21H
	
	MOV AH,2
	MOV DL,shi
	INT 21H
	
	MOV AH,2
	MOV DL,g
	INT 21H
	 
    MOV AH,4CH
    INT 21H

输入多位数

利用1号功能的循环输入多位数,用空格分割数字

ASSUME CS:CODES,DS:DATAS

DATAS SEGMENT
   buf DW 100 dup(?)       ;预留100个数组元素
   COUNT DW ?      ;数组元素个数
   error DB 13,10,'input error',13,10,'$'
DATAS ENDS


CODES SEGMENT

START:

	MOV AX,DATAS
	MOV DS,AX
	
	MOV SI,0
	MOV DI,0
	
	MOV BX,0
	
input:	

	MOV AH,1
	INT 21H
	
	.IF AL == 13	;回车退出
		JMP exit1
	.ELSEIF AL== 32	;空格输入下一组数据
		JMP lp1
	.ENDIF
	
	.IF AL < '0'
		JMP e
	.ELSEIF AL > '9'
		JMP e
	.ELSE			; 40 - 49 得到输入的真实数值,并把两位数存入BX中
		SUB AL,30H	;从ASCII码得到真实数字

      	CBW			;将AL拓展为AX
      	XCHG  AX, BX   

     	MOV   CX, 10
      	MUL   CX
      	XCHG  AX, BX
      	ADD   BX, AX
      	JMP input      
		
	.ENDIF
	
lp1:
	;存数据
	MOV buf[SI],BX
	MOV BX,0
	INC SI
	INC SI
	INC DI
	
	MOV COUNT,DI		;记录输入的个数
	
	JMP input
			
		
e:		;错误提示
	MOV AH,9
	LEA DX,error
	INT 21H	
	
	JMP finish
		
exit1:
	MOV buf[SI],BX  ;存入最后一个数
finish:	
	MOV AH,ACH
	INT 21H

22.9.7. 汇编中数的存储

  • 调用输入功能,输入的数字,是以ASCII码的形式存的,在运算时要先减30H
  • 直接在程序中定义的数字,是已数字的形式存的,输出时要输出它的字符串形式,要加30H

22.10. 位操作指令

逻辑运算和移位运算都用二进制来进行

22.10.1. 逻辑运算

适用于有符号数和无符号数

AND

格式:
AND mem,imm/reg ;
AND reg,imm/reg/mem ;

注意:
均为1才为1,否则为0
AND 指令可用于屏蔽某些位(用0相与)
AND指令设置CF = OF = 0,根据结果设置SF、ZF和PF状态,而对AF未定义

OR

格式:
同上

注意:
有1为1,否则为0
OR 指令可用于置位某些位(用1相或)
标志的影响同AND指令

XOR

格式:
同上

注意:
相同为0,不同为1
XOR 指令可用于求反某些位(用1相异或)
标志的影响同AND指令

NOT

格式:
NOT reg/mem

注意:
取反
NOT指令是一个单操作数指令
NOT指令不影响标志位

TEST

对两个操作数执行逻辑与运算,结果不回送到目的操作数
标志的影响同 AND 指令

常用操作

  • 使用TEST 数字和大小写字母的判断
大写字母A-Z: 01000001B - 01011010B		
小写字母a-z: 01100001B - 01111010B
数字0-9:     00110000B - 00111001B

数字和字母的第6位不同,TEST AL,40H,第6位为0是数字,第6位为1是字母

大小写字母的第5位不同,TEST AL,20H,第5位为0是大写字母,第5位为1是小写字母
  • 使用TEST 正数、负数、奇数、偶数的判断
偶数的特点是换算成二进制的话最后一位必定是0(2的倍数),所以检测最后一位是否是0就能判断出是否是偶

有符号数的第一位用0代表正,1代表负
  • 使用AND将键盘输入的小写字母转为大写
AND AL,0DFH

22.10.2. 算术移位指令

如果移位超过1,必须使用CL寄存器存放移位的位数

适用于有符号数

SAL左移

算术左移,最高位进入CF,最低位补0

SAR右移

算术右移,最低位进入CF,最高位不变

22.10.3. 逻辑移位指令

使用于无符号数

SHL左移

逻辑左移,最高位进入CF,最低位补0

SHR右移

逻辑右移,最低位进入CF,最高位补0

移位指令对标志的影响

按照移入的位设置进位标志CF

对AF没有定义

如果移位次数为1,则按照操作数的最高符号位是否改变,相应设置溢出标志OF:如果移位前操作数最高位与移位后不同则OF = 1;否则OF = 0。

当移位次数大于1时,OF不确定

22.10.4. 循环移位指令

功能:
将操作数从一端移出的位返回到另一端形成循环,分成不带进位和带进位,分别具有左移或右移操作。

格式:
ROL reg/mem,1/CL	不带进位循环左移
ROR reg/mem,1/CL	不带进位循环右移
RCL reg/mem,1/CL	带进位循环左移
RCR reg/mem,1/CL	带进位循环右移

ROL

最高位移入CF,同时将操作数从首端移出的位返回到末端形成循环
如:
MOV AL,8AH	;10001010
ROL AL,1	;00010101

ROR

最低位移入CF,同时将操作数从末端移出的位返回到首端形成循环
如:
MOV AL,8AH	;10001010
ROR AL,1	;01000101

RCL

操作数和进位一起循环左移,CF移入最低位,同时最高位移入CF

RCR

操作数和进位一起循环右移,CF移入最高位,同时最低位移入CF

22.10.5. 总结

用右移实现除法时,会出现余数丢失

22.11. 转移指令

22.11.1. CMP相关

可进行两种比较,有符号数比较和无符号数比较,所以转移也分两种,无符号比较结果根据(zf、cf的值),有符号数比较根据(sf、of、zf的值)

无符号数比较

CMP i,j


JE 标号		;i == j 则跳转   检测 zf=1
JNE 标号		;i != j 则转移  检测 zf=0

JB 标号		;i < j 跳转	检测 cf=1
JNB 标号		;i >= j 跳转	检测 cf=0

JA 标号		;i > j 跳转   检测 cf=0且zf=0
JNA 标号		 ;i <=j 跳转	检测 cf=1或zf=1

JZ 标号		; i == j 跳转


注意:
e 表示 equal 等于
b 表示 below 小于
a 表示 above 大于
n 表示 no 否

有符号数比较

JL	小于			SF!=OF且ZF=0
JLE 小于等于	   SF!=OF或ZF=1

JG				SF=OF且ZF=0
JGE				SF=OF或ZF=1

G greater 大
L less    小

22.11.2. 条件标志转移

指令结果影响标志位

JZ (JE) 	结果为0或相等   	ZF=1
JNZ (JNE) 	结果不为0或不相等  ZF=0

JC 		    结果有进位		 CF=1
JNC			结果无进位		CF=0

JS			结果为负		 SF=1
JNS			结果为正		 SF=0

JO			结果溢出		 OF=1
JNO			结果无溢出		OF=0

JP			结果为偶数个1	    PF=1
JNP			结果为奇数个1		PF=0

22.11.3. CX相关

格式:JCXZ OPR
若CX=0则转移

22.12. 循环指令

对状态标志位都没影响

22.12.1. LOOP

  • CX = CX - 1
  • CX != 0 时循环

22.12.2. LOOPZ/LOOPE

  • CX = CX - 1
  • CX != 0 且 ZF = 1 时循环,ZF = 0 提前退出循环

22.12.3. LOOPNZ/LOOPNE

  • CX = CX - 1
  • CX != 0 且 ZF = 0 时循环,ZF = 1 提前退出循环

22.13. 串操作指令

22.13.1. 指令格式

唯一源和目标可同时为寄存器的操作指令

显式:MOVS  DST, SRC	
隐式:MOVSB	  ;字节传送
     MOVSW		;字传送
     MOVSD		;双字传送

22.13.2. 操作数

串指令可以处理累加寄存器和存储器操作数。对于存储器操作数应先建立地址指针:

	若为源操作数,则必须把DS:源串首地址放入SI寄存器,缺省情况寻址DS段

    若为目标操作数,则必须把ES:目标串首地址放入DI寄存器,不允许使用段超越前缀

22.13.3. 地址指针

串指令执行后自动修改地址指针SI、DI

22.13.4. 方向标志

方向标志DF决定地址指针的增减

CLD 指令 使 DF = 0

STD 指令 使 DF = 1

 
   若DF=0,则地址指针增量
   若DF=1,则地址指针减量

22.13.5. 重复前缀

串指令前可以加重复前缀REPE/REPZ、 REP或REPNE/REPNZ,使后跟的串指令重复执行

重复次数应事先初始化在计数器CX中

串操作指令的重复前缀和LOOP对应

REP :重复串操作,直到(CX) = 0

REPZ/REPE :结果为0或相等则重复。若CX != 0 且 ZF = 1,则重复,(CX) = (CX) - 1,直到(CX) = 0。如果结果不为0或不相等则提前退出,此时CX还没减为 0,SI和DI已经增量

REPNZ/REPNE :结果不为0或不相等则重复。若CX != 0 且 ZF = 0,则重复,(CX) = (CX) - 1,直到(CX) = 0。如果结果为0或相等则提前退出,此时CX还没减为 0,SI和DI已经增量

22.13.6. 操作指令

串操作指令应该和重复前缀一起使用,但不是所有串操作指令前都可以加重复前缀

串操作指令和重复前缀,其中先执行串操作指令,后执行重复前缀

串传送

不影响标志位
MOVS  DST, SRC
REP MOVSB 以字节形式重复传送

串比较

结果不回送,改变标志位
CMPS
REPE CMPSB 以字节形式重复比较

串扫描

结果不保存,影响标志位
在目的串中查找与AL、AX中相同或不同的字节或字
SCAS DST
SCASB

串获取

前面不加重复指令
不影响标志位
从源串中取出字或字节放入AL、AX中
LODS SRC
LODSB

串存入

将AL、AX内容存入目的串中
STOS DST

22.14. 高级汇编指令

22.14.1. IF语句

.IF 条件表达式 
               分支体
 [.ELSEIF 条件表达式 
               分支体 ]
 [.ELSE
            分支体 ]
 .ENDIF ;分支结束
 
 
 例
    .IF ax==5
             mov bx, ax
             mov ax, 0
    .ELSE
             dec  ax
    .ENDIF

22.14.2. WHILE语句

           .WHILE 条件表达式 
                  循环体
           .ENDW
 UNTIL结构格式为:     >=类是按无符号数
           .REPEAT
                  循环体
           .UNTIL 条件表达式 
 UNTIL结构还有一种格式:
           .REPEAT 
                  循环体
           .UNTILCXZ [条件表达式] 
          ;cx←cx-1,直到cx=0或条件为真

22.15. 汇编错误汇总

.MODEL must precede this directive                           .MODEL必须在指令之前
[ELSE]IF2/.ERR2 not allowed : single-pass assembler          [ELSE]IF2/.ERR2不允许单独汇编
assembler limit : macro parameter name table full      汇编限制:宏参数名表已满
can ALIGN only to power of 2                    仅能对齐到2的幂
cannot access label through segment registers        在段寄存器中不能存取标记
cannot access symbol in given segment or group        在特定的段或类不能存取符号
cannot add memory expression and code label                  不能增加内存表达式和代码标记
cannot add two relocatable labels                         不能增加双重转移表标记
cannot define as public or external                     不能定义为公有或外部的
cannot find cvpack.exe                          找不到cvpack.exe
cannot find link.exe                              找不到连接程序
cannot have more than one ELSE clause per IF block            IF段只能有一个ELSE从句
cannot mix 16- and 32-bit registers                 不能结合16位和32位寄存器
cannot open file 不能打开文件
COFF error writing file                      COFF错误,正在写文件
constant expected                         连续预期
constant or relocatable label expected                       预期的转移表或连续的
constant value too large             连续标准太多
count must be positive or zero                              计数必须是零或明确的
count value too large                                        计数标准太多
directive must be in control block                指令必须在控制段
distance invalid for word size of current segment           当前区、段的大小命令无效
DUP too complex                          DUP太复杂
empty (null) string                没有字符串
END directive required at end of file                        END指令必须在文件结尾
error count exceeds 100; stopping assembly             错误数超过100,停止汇编
expected               预定义  
expression expected                   预期表达式
expression must be a code address             表达式必须是一个代码地址
expression too complex for .UNTILCXZ             .UNTILCXZ表达式太复杂
extra characters after statement                           附加的字符在声明之后
FATAL   严重错误
forced error                           强制错误
forced error : string blank                   字符串是空的
forced error : string not blank             字符串不是空的
forced error : strings equal              字符串是相同的
forced error : strings not equal              字符串不是相同的
forced error : symbol defined               符号已定义
forced error : symbol not defined            符号没有定义
forced error : value equal to 0                 标准等于零
forced error : value not equal to 0             标准不等于零
I/O error closing file I/O错误 正在关闭文件
I/O error reading file            I/O错误 正在读取文件
I/O error writing file I/O错误 正在写文件
identifier not a record                      没有记录标示符
identifier too long                       标识符太长
immediate operand not allowed                      当前操作数无法载入
incompatible CPU mode and segment size              不匹配的CPU模式和段尺寸
index value past end of string                              索引标准在字符串结尾之后
initializer magnitude too large for specified size        初始指定尺寸太大
instruction does not allow FAR direct addressing       指令不允许远直接寻址
instruction does not allow FAR indirect addressing      指令不允许远间接寻址
instruction does not allow NEAR indirect addressing      指令不允许近间接寻址
instruction form requires 80386/486                 指令需要80386/486指示   
instruction operand must have size             命令操作数必须有长度
instruction operands must be the same size        命令操作数必须是一样的长度
instruction or register not accepted in current CPU mode   当前CPU模式不认可的指令或寄存器
instruction prefix not allowed                    不允许的命令前缀
Internal Assembler Error                         内部汇编错误
invalid character in file                 文件里有无效字符
invalid command-line option           无效命令行参数
invalid debug and browser data; file exceeds line limit        不能排除故障和浏览数据;文件超过行限制
invalid instruction operands                   无效的指令操作数
invalid INVOKE argument                   无效的INVOKE符号
invalid numerical command-line argument                无效命令行参数
invalid operand for OFFSET                                    OFFSET操作数无效
invalid operand size for instruction            操作数长度对于指令无效
invalid scale value                                无效范围标准
invalid type expression                      无效的类型表达式
invalid use of external absolute                             由于完全外部的使用无效
invalid use of external symbol               使用了无效的外部符号
invalid use of register                     使用的寄存器无效
jump destination must specify a label           跳转目标必须指定一个标记
jump destination too far                            跳转目标太远
jump distance not possible in current CPU mode       跳转距离不适合当前CPU模式
line too long
line too long                  行太长
LOCK must be followed by a memory operation          LOCK指令必须跟在内存操作之后
memory operand not allowed in context                  内存操作数无法载入上下文环境
missing angle bracket or brace in literal         语句里找不到同样的括弧或框架
missing operand after unary operator                 一元运算符之后找不到操作数
missing operand for macro operator             找不到宏的操作数
missing single or double quotation mark in string          找不到单引号或双引号
missing source filename                                找不到源文件名
multiple base registers not allowed             不允许多重基础寄存器
multiple index registers not allowed           不允许多重标志寄存器
must be in segment block                  必须在区、段、块中
must be index or base register                  必须是基础或标志寄存器
nesting level too deep             嵌套过深
no operands allowed for this instruction          指令没有操作数
non-benign record redefinition                      没有利于记录的定义
nondigit in number                   没有总数
operand must be a memory expression             操作数必须是一个内存表达式
operand must be RECORD type or field            操作数必须是RECORD类型或域
operand must be relocatable                                  操作数必须是转移表
operands have different frames                  操作数存在不同的结构
operands must be in same segment              操作数必须在相同的段
operator expected                      预期操作数
out of memory              缺少内存
positive value expected                                      预期的明确的标准
PROC, MACRO, or macro repeat directive must precede LOCAL    PROC, MACRO, 或 macro repeat指令必须在LOCAL之前
real or BCD number not allowed                不允许real或BCD编码
record constants may not span line breaks                 连续记录不能超过行间隔
reserved word expected                      预期的保留字
segment attributes cannot change                        区、段属性不能更换
segment expected                                                预期的区段
segment or group not allowed                               区段或类型不允许
segment register not allowed in context            上下文不允许有寄存器
segment, group, or segment register expected                   预期的段,类型或段寄存器
SEVERE                              严重的错误
statement not allowed inside structure definition         声明不允许在结构里面
statement too complex                                   声明太复杂
statement too complex                    声明太复杂
string or text literal too long                 文本或字符串太长
structure alignment must be 1, 2, 4, 8, or 16             结构对齐必须是1,2,4,8或16
symbol redefinition                         符号已经定义
symbol type conflict                             符号类型冲突
syntax error                                语法错误
syntax error in expression                   表达式存在语法错误
syntax error in floating-point constant           不确定的指向中有语法错误
text item required                       必须的文本项
too many arguments                                     太多参数、定义、冲突
too many bits in RECORD                                      太多位在记录里
too many initial values for structure                太多结构的基础资料
undefined symbol                        符号没有定义
unmatched block nesting                   不正确的区、段嵌套
unmatched macro nesting            不正确的宏嵌套

本站总访问量