第三章 汇编语言指令集
一、基本概念
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除数=ALAH
字除法:DXAX除数=AXDX 与字节除法的存储方式类似,余数覆盖高位的被除数,商覆盖低位的被除数。
(里面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),增址传送
处理机控制指令,没学叭
写的挺急的,估计有不少错误和遗漏的地方。
例1 关于POP、PUSH、CALL的练习:
设AX=1234H,BX=5678H
MOV SP,2000H
PUSH AX
PUSH BX
CALL SUB1(段内调用)
POP CX
POP DX
...
SUB1 PROC
MOV BP,SP
MOV AX,[BP+2]
MOV BX,[BP+4]
RET
SUB1 ENDP
程序段执行后,SP=2000H,AX=5678H,BX=1234H。
首先,PUSH进栈,(SP)-2->(SP); 尤其注意,CALL指令在调用时,将断点的偏移地址压入堆栈中保存,
然后将偏移地址->(IP), (SP)-2->(SP).
CALL指令也会修改SP!虽然SP-2之后不知道指向元素是谁,但是确实修改了SP!
例2 实际是我没记住
执行段内调用指令CALL XXH,先将断点地址压入堆栈,然后将嗲用地址XXH存入IP寄存器。
除法指令DIV BX,被除数默认放在 DX、AX中,商存放在AX中
汇编程序开发经历 编辑、汇编、链接 三个阶段,两种不同的编程格式生成的可执行文件扩展名分别为.com .exe
例3 DB和DW中字符的存储
如果是DB,存储的'HELLO',,直接顺着放
如果是DW,只能存储单引号括起来的一个或者两个字符
例4 PTR运算符
BUF DB 11,22,33,44
MOV AX,BUF
这里,不能修改PTR修饰AX啊,得修饰BUF
关于PTR的双操作数指令:
①源操作数是立即数,目标操作数为直接寻址,类型不一致时,只能修改直接寻址的存储器操作数
②有一方为直接寻址,类型不一致时,只能修改存储器操作数
③除直接寻址外的存储器操作数寻址,都必须用PTR
为什么感觉1和2是包含关系。
直接寻址,可以根据情况给PTR;除了直接寻址外的存储器操作数寻址,一定要给PTR;PTR只能修改存储器操作数