本文转载自厉害的
孔姐姐
的 博客 。由一只孔姐姐的小迷弟负责排版和整理~
一、基本概念
1.指令:单个的 CPU 操作,通知 CPU 执行某种操作的 “命令”
-
指令集:所有指令的集合
-
机器指令:用二进制序列(0、1)代码书写。硬件只能识别、存储和运行机器指令
-
符号指令:用字符串形式的序列(包含字符串形式的操作码、操作数)
2.指令的组成:操作码 + 操作数
-
指令长度:机器指令长度为 1~16 字节
-
指令地址:多字节指令会占用连续的内存单元,存放指令第一个字节的内存地址,称为
指令地址
-
指令存放:
- 多字节的操作数连续存放,规则遵循
小端法
- 低字节存放在低地址单元,高字节存放在高地址单元。
- 多字节的操作数连续存放,规则遵循
-
指令格式:
3.操作数:指令的操作对象(输入数据、输出数据)----> 存放于 CPU 寄存器、计算机的存储器、接口电路中的端口
(1)寄存器操作数:存放于通用寄存器(8 个)中
(2)段寄存器和程序指针: CS:IP 决定取哪条指令
(3)标志存储器:分 状态标志
、控制标志
- 状态标志
C:最高位产生 借位或进位标志。进位 C=1
O:溢出标志。溢出 O=1
Z:零标志。结果为 0 则 Z=1
S:符号标志。就是结果的符号位。
P:奇偶标志。低 8 位中 1 的个数为偶数 P=1
A:辅助进位标志。低半字节向高半字节有进位或借位,A=1
- 控制标志
D:方向标志。D=1 时串操作时自动减量
I:中断标志。I=1 时允许 CPU 接收外部的中断请求
T:陷阱标志。T=1 时进入单步调试状态。
注意 O 标为 0,加数与被加数是 1,结果也是 1,相同。O 标为 0
但是,在讨论是否溢出的时候,就要分情况讨论了。(有 O,无 C)
二、寻址方式
1.操作数的存在方式(4 种)
-
立即数:包含在指令中 ------------ 立即寻址
-
寄存器操作数:存放于 CPU 的某个寄存器中 ---------------- 寄存器寻址
-
内存操作数:存放于存储器中 ------------------ 存储器寻址
-
I/O 端口操作数:存放于 I/O 端口中
2.立即寻址:
MOV AL,OFFSET BUF ;(是不是可以理解成,取出了偏移量,就取得了操作数)
MOV CX,0A234H ;( A~F 开头的数字,加上 0 作为前缀)
3.寄存器寻址:存放在寄存器中
MOV EAX,12345678H
INC SI
4.存储器寻址(内存操作数寻址): 5 种
使用段页式管理部件,将指令中的逻辑地址转化为对应的物理地址,(对应第二章实模式下,存储地址空间)再通过总线系统访问实际的物理存储单元。
- 段寄存器名称 : 偏移地址表达式
段寄存器名称,也称为段超越前缀,是存放操作数的存储单元所在的逻辑段:如 CS、DS、SS、ES。而这些段寄存器中存放逻辑段的段基址(逻辑段在存储空间中的位置)。 16 位
偏移地址表达式,给出偏移地址,也称偏移量,相对于逻辑段段首单元的地址偏移量。16 位
- 操作数的物理地址 = 段基址 * 16 + 偏移地址
(1)直接寻址:偏移地址 用数值、变量名表示
ADD AL,DS:[45H] ;这里段寄存器名称一定要加
MOV AX,ES:[1000H]
MOV AX,DS:BUF ;也可以写成 MOV AX,BUF
INC BUF+2
用变量名代表偏移地址,变量名在汇编的时候,会给出实际的偏移地址,所以 BUF+2,BUF 都是直接寻址。
(2) 寄存器间接寻址:间接寻址、间址
注意,这里是要从内存中取操作数,但是通过寄存器找的而已,差不多这意思?
MOV AX,[BX]
MOV AX,[SI]
但是,只有一些指定的通用寄存器能够作为间址寄存器使用
(3)基址寻址:
MOV AX,[BX+2]
同样,只用一些特别指定的通用寄存器可以作为基址寄存器使用
(4)变址寻址:
MOV AL,[SI+2]
有比例因子的变址寄存器的寻址位数都是 32 位的(就是 E。。。)
无比例因子的变址寻址方式只能使用 SI、DI
MOV SI,BUF 单元的偏移地址
MOV AH,SS:[SI+3]
(5) 基址 + 变址寻址:
MOV AL,[BX+SI+2]
总结一下寻址方式:
-
BX、SI、DI 对应的一定是数据段,BP 对应的一定是堆栈段
-
SI、DI 不能做基址寄存器。 [SI] 是间址, [SI+3] 是变址,[BX] 是间址,[BX+3] 是基址。
-
[BX]、[SI] 是间址
-
[DX] 是不对的,没有 DX 的寄存器
三、汇编语言语法(名字项、操作数项、操作项)
1.可执行文件的生成(考察后缀名,过程)
源程序 ------------ .asm ----------------------- .obj --------------------- .exe
EDIT 编辑 TASM 汇编 TLINK 链接
-
.exe
-
.com
2.语句类型:指令性语句 指示性语句
指令性语句: 符号指令(机器指令):CPU 执行
指示性语句:伪指令和宏指令
- 伪指令:数据定义伪指令、符号定义伪指令。汇编工具执行,为汇编工具提供信息,例如计算出某个逻辑段的段基址。有 DB/DW/DD、EQU、SEGMENT、END 等等。
3.名字项:有标号和变量 2 种类型。又称符号地址,都有段属性、偏移属性、类型属性三种。
JUMP 标号 ;这里的标号就是符号地址
标号:定义在代码段中。
变量:定义在 DS、SS、ES 中
4.操作项:操作码助记符(MOV SUB…)、伪指令助记符
数据定义伪指令: DB DW DD DF/DQ/DT
符号定义伪指令:EQU =
注意的点:
①DB 可以定义用单引号括起来的很长的字符串,但是都是按照从上往下,地址由低向高排的
但是 DW 只能存单引号括起来的一个或者两个字符
5.操作数项:包括数值表达式、地址表达式
(1)数值表达式:标号和变量、常量(立即数、字符串常数、符号常数)、数值运算符(算术运算符、逻辑运算符、关系运算符、数值回送运算符)
字符串常数是用单引号括起来的一个或多个字符,在汇编结束后,会转换成对应的 ASCII 码。'12’会转换为 3132H。
关系运算只能对两个数字,或者同一个逻辑段的两个存储单元中的数。如果为真,则结果为 0FFFF H,,假的结果为 0
数值回送运算符中:
-
SEG 取出数据段的段基址
-
OFFSET 取出,在逻辑段中相对于段首的偏移地址
-
$ 返回当前汇编地址计数器的值
MOV AX,SEG DATA ;SEG 可省略
MOV AX,SEG DATA
MOV DS,AX
BUF DB 10H,20H,30H
MOV BX,OFFSET BUF
MOV AH,[BX+1]
执行后(AH)=20H
BUF DB 'HELLO NUPT'
COUNT EQU $-BUF
汇编结束后,COUNT 的值为 10
(2)地址表达式:汇编结束后,是变量或者标号所在逻辑段的偏移地址值
包括 方括号运算符 [] 和变量的地址表达式、属性操作符(PTR、LOW/HIGH、SHORT、THIS)
MOV AH,BUF[1]
;等效于
MOV AH,BUF+1
PTR 操作符:
属性不对,必须用 PTR
(源操作数是立即数),除了直接寻址的内存操作数,都必须加 PTR
(5)操作项:包括操作码助记符、伪指令助记符
伪指令:数据定义伪指令(DB DW DD)、数据定义伪指令(EQU = )
四、汇编语言指令集
传送指令、算术运算指令、转移和调用指令、逻辑运算和移位指令、串操作指令、处理机控制指令
1.传送类指令
通用传送:MOV MOVSX MOVZX LEA 指针传送指令 LAHF/SAHF XCHG
MOV XCHG 源目操作数不能同时为内存操作数,不能将立即数直接传送到段寄存器
堆栈操作指令 PUSH POP , 栈底是高地址单元。
PUSH 之后,(SP) - 2 -> (SP) ; POP 之后,(SP) + 2 -> (SP)
这里有些例题,挺有意思的
2.算术运算类指令
-
ADD SUB 不能同时为内存操作数,不能同时为段寄存器 ADC SBB 为二进制数带进位
-
INC DEC:
INC [BX],单操作数,直接寻址必须加 PTR -
NEG:求补指令,但是不是求补码! 0 - 目标操作数
-
MUL 乘数
字节乘法: AL ---->AX AL×乘数 = AX
字乘法:AX—>DXAX 高位 DX, 低位 AX AX×乘数 = DXAX
双字乘法:EAX---->EDXEAX
- DIV 除数
字节除法:被除数 AX,商 AL, 余数 AH AX÷除数 = AL···AH
字除法:DXAX÷除数 = AX···DX 与字节除法的存储方式类似,余数覆盖高位的被除数,商覆盖低位的被除数。
(里面 2 个,外面 2 个,成对覆盖,方便记忆。。。)
- CMP 比较指令 (CMP X,Y X-Y)
CMP BYTE PTR [BX],45H
JC NEXT
- BCD 码调整指令
我认为考试应该只考组合 BCD 码(比如 8421 码),希望不要打脸,我要复习不完了。。。
记得第一章有 BCD 码的结果调整方法:
低四位有进位,+06H
低四位非法,+66H
高四位非法,+60H
我们在给计算机在存储数值的时候,都是用的 XXH,如果直接 ADD AX,BX, 那么进行的是真实的, 16 进制的加法。09H+06H=0FH
如果需要进行 BCD 码运算,就得用到 BCD 码的调整指令。09H +06H =15H
(这里为什么有 H 啊,H 不是十六进制数吗?其实可以这样理解,BCD 码中的 H 是没有实际意义的,只是为了方便 BCD 码的简写)
;用算术运算指令实现十进制的计算1234+5678
N1 DW 1234H
N2 DW 5678H
SUM DW ?
;-----字加----
MOV AX,N1
ADD AX,N2
DAA
MOV SUM,AX
;-----字节加----
MOV AL,BYTE PTR N1
ADD AL,BYTE PTR N2
DAA
MOV BYTE PTR SUM,AL
MOV AL,BYTE PTR N1+1
ADD AL,BYTE PTR N2+1
DAA
MOV BYTE PTR SUM+1,AL
3.转移和调用指令
包括:无条件转移 JMP 、条件转移指令、子程序调用与返回指令、软件中断与返回指令
JMP 标号 只考察段内直接转移(只修改 IP,CS 值不变) 标号是符号指令的地址
条件转移指令有 3 个表格要记(根据状态位的,无符号数的,有符号数的)
这三个表里,JC(C=1)、 JZ(Z=1)、 JNC、 JNZ
JA(jump above) JC(C=1)
JG(jump greater,x>y) JGE(x>=y) 常用
LOOP:
MOV CX,5
AGAIN:
....
LOOP AGAIN
子程序 XYZ 调用: CALL XYZ
掌握段内直接调用,其原理是,首先将 CALL 指令的下一条指令的地址,即断点的偏移地址压入堆栈中保存,然后将子程序的入口偏移地址 ->(IP),(SP-2)->SP,程序由主程序转到子程序
;主函数中
CALL XYZ
;子程序
XYZ PROC
....
....
....
RET
XYZ ENDP
软件中断与返回指令:
INT n
在第四章中,会疯狂地用到
4.逻辑运算和移位指令
-
取反 NOT
-
与运算 AND:使特定位为 0
-
或运算 OR:使特定位为 1
-
XOR:使特定位取反,,,用 1 异或 x, 对 x 取反
-
TEST:测试,
与
运算,影响标志位
移位指令;
开环:SAL SAR SHL SHR
闭环:RCL RCR ROL ROR
左移、右移看最后一个字母 left or right
逻辑、算术运算看中间 algorithm
带 R 的是有循环 recycle?
有符号数 – 算术右移补符号位
开环的左移一定都补 0,因为毕竟左移是要乘 2 的
闭环带 C 的,那就是含进位的,左移出来的那一位,不仅给了 C,也循环到了第 0 位
5.串操作指令
这里,应该是只要掌握
①源串定义在数据段,用 SI 间址访问
②目标串定义在附加段,用 EI 访问
③D=1(STD 使得 D=1),减址传送 D=0(CLD 使得 D=0),增址传送