一、进制转换
1.二进制转为十进制:
方法:按权相加法,即将二进制每位上的数乘以权,然后相加之和即是十进制数。
例:(101.101)2=(5.625)10
2.十进制转为二进制:
1)整数部分:
方法:除2取余法(短除法),即每次将整数部分除以2,记录余数,而商继续除以2,继续记录余数,这个步骤一直持续下去,直到商为0为止,最后读数时候,逆序读每一个余数。下面举例:
例:将十进制的168转换为二进制
得出结果 将十进制的168转换为二进制,(10101000)2
分析:第一步,将168除以2,商84,余数为0。
第二步,将商84除以2,商42余数为0。
第三步,将商42除以2,商21余数为0。
第四步,将商21除以2,商10余数为1。
第五步,将商10除以2,商5余数为0。
第六步,将商5除以2,商2余数为1。
第七步,将商2除以2,商1余数为0。
第八步,将商1除以2,商0余数为1。
第九步,读数,因为最后一位是经过多次除以2才得到的,因此它是最高位,读数字从最后的余数向前读,即10101000
2) 小数部分
方法:乘2取整法,即将小数部分乘以2,然后取整数部分,剩下的小数部分继续乘以2,然后取整数部分,剩下的小数部分又乘以2,一直取到小数部分
为零为止。如果永远不能为零,就同十进制数的四舍五入一样,按照要求保留多少位小数时,就根据后面一位是0还是1,取舍,如果是零,舍掉,如果是1,向入一位。换句话说就是0舍1入。读数要从前面的整数读到后面的整数,下面举例:
例1:将0.125换算为二进制
得出结果:将0.125换算为二进制(0.001)2
分析:第一步,将0.125乘以2,得0.25,则整数部分为0,小数部分为0.25;
第二步, 将小数部分0.25乘以2,得0.5,则整数部分为0,小数部分为0.5;
第三步, 将小数部分0.5乘以2,得1.0,则整数部分为1,小数部分为0.0;
第四步,读数,从第一位读起,读到最后一位,即为0.001。
3.在二进制与八进制、十六进制转化的时候,三位二进制位对应一位八进制位,四位二进制位对应一位十六进制位。
4.其他进制间的转化可以借助十进制与二进制的转化。
二、原码、反码、补码
1.原码即真值+符号位。反码即原码取反。补码即反码+1。
2.由负数的真值或原码变补码的方法:自最低位向高位逐位检查,遇到第一个‘1’及以前(较低位)的各位‘0’保持不变,以后各高位取反。若是原码变补码,因最高位为符号位,不改变。
3.内存里皆以补码表示。对一个数求补,即求负。
4.反码算数运算若有进位则要回送给最低位,而补码算数运算若有进位则舍弃。
三、寄存器
1、寄存器汇总
AX(AH、AL)累加器;
BX(BH、BL)基址寄存器;
CX(CH、CL)计数寄存器;
DX(DH、DL)数据寄存器;
SP 堆栈指针;
BP 基址指针;
SI 源变址寄存器;
DI 目的变址寄存器;
IP 指令指针;
FLAGS 标志寄存器;
CS 代码段寄存器;
DS 数据段寄存器;
SS 堆栈段寄存器;
ES 附加段寄存器。
其中,通用寄存器有:AX,BX,CX,DX,SP,BP,SI,DI。
2、标志寄存器的各标志位(复位(0)、置位(1))
1)溢出位OF,置位OV,复位NV。判断运算结果是否超出补码范围。溢出则置位。
2)方向位DF,置位DN,复位UP。决定串操作指令执行时指针寄存器的调整方向。DF=0时,正向处理(低位->高位),SI/DI递增。反之,亦然。
3)中断位IF,置位EI,复位DI。
4)符号位SF,置位NG,复位PL。与运算结果的最高位相一致。
5)零值位ZF,置位ZR,复位NZ。若运算结果为0,置位。否则,清0。
6)辅助进位位AF,置位AC,复位NA。若低4位出现进位或者借位,置位。否则,清0。
7)奇偶位PF,置位PE,复位PO。若运算结果低8位中‘1’个数为偶,则置位。否则,清0。
8)进位位CF,置位CY,复位NC。若最高位进位或者借位,则置位。在移位类指令中用来保存移出的0或1。
四、存储器的段结构
1.逻辑段的开始地址必须是任一小节的首地址。自0地址开始,每16字节为一小节。1MB的存储空间为65536小节。
2.逻辑段最大为1MB,最小为16B。
3.物理地址=16位段基值*16+偏移量
五、堆栈
1.在x86中,堆栈向下增长,是按字组织的,即最小数据单元为一个字。
2.当SP初始化时,它指向栈底+2字节单元,它的值就是这个堆栈的长度。
3.BP作为基址,一直不变;而SP作为栈顶指针,随栈顶的移动而移动。
4.压栈:PUSH。两步:SP<=SP-2;SP<=数据。
出栈:POP。两步:数据单元<=SP;SP<=SP+2。
PUSHF:将标志寄存器内容压栈。
POPF:将栈顶一个字数据送入标志寄存器。
六、传送类指令:源操作数与目的操作数类型必须一致(即同一个字节或字大小)。
1.MOV:MOV DEST,SRC 功能:DEST<=SRC。
源操作数与目的操作数不可同时为存储单元。对FLAGS没有影响。
2.XCHG:XCHG DEST,SRC 功能:交换DEST与SRC内容。
源操作数与目的操作数不可同时为存储单元。对FLAGS没有影响。
3.LAHF:LAHF 功能:将FLAGS低8位传送至AH,即把SF,ZF,AF,PF,CF分别传送至AH的第7,6,4,2,0位,AH其他位任意值。
对FLAGS没有影响。
4.SAHF:SAHF 功能:将AH的内容送入FLAGS低8位。
只影响SF,ZF,AF,PF,CF位。
5.PUSHF:PUSHF 功能:将标志寄存器内容压栈。
对FLAGS没有影响。
6.POPF:POPF 功能:将栈顶一个字数据送入标志寄存器。
影响FLAGS所有的位。
7.LEA:LEA DEST,SRC 功能:将SRC的有效地址EA送入DEST。其中,SRC必须为一个字节或字的存储器操作数,DEST必须为一个16位的通用寄存器。
对FLAGS没有影响。
8.LDS/LES:LDS/LES DEST,SRC 功能:将SRC所指32位存储单元的低16位送入DEST,而高16位送入DS(LDS指令)或ES(LES指令)。其中,DEST必须为一个16位通用寄存器,SRC必须是一个存储器操作数,该地址单元中存放着32位地址,低16位是偏移量,高16位是段基址。
对FLAGS没有影响。
9.XLAT (OPR):XLAT (OPR) 功能:AL<=[BX+AL],即将BX与AL相加形成EA,再将地址对应的字节存储单元内容送入AL中。OPR可写可不写,没有实际作用,只是为了增加程序可读性而设置的,其内容为一个偏移量,和BX内容相同,存放一个表格的首地址。
对FLAGS没有影响。
七、算术运算类指令(不含乘除):源操作数与目的操作数类型必须一致(即同一个字节或字大小)。
1.ADD:ADD DEST,SRC 功能:DEST<=DEST+SRC
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的CF、PF、AF、ZF、SF和OF位。
2.ADC:ADC DEST,SRC 功能:DEST<=DEST+SRC+CF。带进位的加法。
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的CF、PF、AF、ZF、SF和OF位。
3.INC:INC DEST 功能:DEST<=DEST+1 其中,DEST可以为通用寄存器,也可以为存储单元。
该指令会根据运算结果设置FLAGS的PF、AF、ZF、SF和OF位,但不影响CF位。
4.SUB:SUB DEST,SRC 功能:DEST<=DEST-SRC
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的CF、PF、AF、ZF、SF和OF位。
5.SBB:SBB DEST,SRC 功能:DEST<=DEST-SRC-CF。带借位的减法。
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的CF、PF、AF、ZF、SF和OF位。
6.DEC:DEC DEST 功能:DEST<=DEST-1 其中,DEST可以为通用寄存器,也可以为存储单元。
该指令会根据运算结果设置FLAGS的PF、AF、ZF、SF和OF位,但不影响CF位。
7.NEG:NEG DEST 功能:DEST<=0-DEST 求补运算,也可以说是求负运算。
若字节操作数为-128(80H)或字操作数为-32768(8000H)时,该指令执行后,操作数不变,OF置位;否则,OF复位。若操作数为0,那么结果不变,CF复位;否则,置位。
该指令会根据运算结果设置FLAGS的CF、PF、AF、ZF、SF和OF位。
8.CMP:CMP DEST,SRC 功能:与SUB基本相同,唯一不同的是目的操作数不变。
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的CF、PF、AF、ZF、SF和OF位。
八、位操作类指令:源操作数与目的操作数类型必须一致(即同一个字节或字大小)
1.AND:AND DEST,SRC 功能:DEST<=DEST&SRC
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的PF、ZF、SF位,CF和OF位总复位,AF位不确定。
2.TEST:TEST DEST,SRC 功能:与AND基本相同,唯一不同的是,DEST不变。常用于测试目的操作数的某一位或某几位的状态。
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的PF、ZF、SF位,CF和OF位总复位,AF位不确定。
3.OR:OR DEST,SRC 功能:DEST<=DEST|SRC
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的PF、ZF、SF位,CF和OF位总复位,AF位不确定。
4.XOR:XOR DEST,SRC 功能:DEST<=DEST^SRC
源操作数与目的操作数不可同时为存储单元。该指令会根据运算结果设置FLAGS的PF、ZF、SF位,CF和OF位总复位,AF位不确定。
5.NOT:NOT DEST 功能:DEST<=~DEST(按位取反)
对FLAGS无影响。
6.SAL:SAL DEST,COUNT 功能:DEST<=DEST<<COUNT 算数左移指令:左移COUNT位,每移动一位,最低位补0,移出的最高位送入CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
该指令会根据运算结果设置FLAGS的CF、PF、ZF、SF和OF位,AF位不确定。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
7.SAR:SAR DEST,COUNT 功能:DEST<=DEST>>COUNT 算数右移指令:右移COUNT位,每移动一位,最高位补原有值,移出的最低位送入CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
该指令会根据运算结果设置FLAGS的CF、PF、ZF、SF和OF位,AF位不确定。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
8.SHL:SHL DEST,COUNT 功能:与SAL完全相同 逻辑左移指令
9.SHR:SHR DEST,COUNT 功能:逻辑右移指令:将DEST右移COUNT位,每移动一位,最高位补0,移出的最低位送入CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
该指令会根据运算结果设置FLAGS的CF、PF、ZF、SF和OF位,AF位不确定。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
10.ROL:ROL DEST,COUNT 功能:循环左移指令:每移动一位,把移出的最高位送入最低位和CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
只影响FLAGS的CF和OF位。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
11.ROR:ROR DEST,COUNT 功能:循环右移指令:每移动一位,把移出的最低位送入最高位和CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
只影响FLAGS的CF和OF位。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
12.RCL:RCL DEST,COUNT 功能:带进位的循环左移指令:每移动一位,把CF位送入最低位,把移出的最高位送入CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
只影响FLAGS的CF和OF位。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
13.RCR:RCR DEST,COUNT 功能:带进位的循环右移指令:每移动一位,把CF位送入最高位,把移出的最低位送入CF位。其中,如果COUNT=1,指令中可直接用1代替COUNT的位置;如果COUNT>1,那么必须用CL来代替COUNT的位置,移位位数由CL决定。
只影响FLAGS的CF和OF位。若移位位数为1次,且移位前后DEST最高位发生变化,则OF置位,否则复位。若移位位数>1,那么OF不确定。
九、标志位操作指令:
1.CLC:CLC 功能:CF=0
2.STC:STC 功能:CF=1
3.CMC:CMC 功能:CF=~CF
4.CLD:CLD 功能:DF=0
5.STD:STD 功能:DF=1
6.CLI:CLI 功能:IF=0
7.STI:STI 功能:IF=1
十、标识符、常量与变量:
1.标识符组成规则:(无大小写区分)
(1)最多由31个字符组成;
(2)必须是以字母、‘?’、‘@’或‘_‘开始;
(3)除第一个字符外,可以是字母、数字、‘?’、‘@’或‘_‘;
(4)不能是系统专用保留字。
2.常量表示:
(1)二进制常量:B(b)后缀;
(2)十进制常量:D(d)后缀,可省略;
(3)八进制常量:Q(q)或O(o)后缀;
(4)十六进制常量:H(h)后缀。对于A~F或a~f开头的十六进制数,必须在其前加一个0,以便与标识符区分开。
(5)实数常量:通常以十进制表示,由整数、小数和指数三部分组成。eg:-1.23E-4;9.0E+4。实数必须由伪指令DD、DQ、DT定义,实数不能出现在表达式中。另外,实数也可以用十六进制数直接说明其二进制数编码形式,但是这个十六进制数必须以0~9开头,不带符号,并在用R作后缀。
(6)字符串常量:用单引号括起来的一个或多个字符。有大小写区分。
3.变量定义:DB(字节变量)、DW(字变量)、DD(双字变量)、DQ(四字变量)、DT(五字变量)。
4.变量属性:
(1)SEG:所在段的段基值;
(2)OFFSET:距离段基址的字节数(偏移量);
(3)TYPE:所占存储单元的字节数。
5.变量预置:
(1)数值表达式:eg:VA DW 1234H,0ABCDH (依次以小尾方式存储,前一个单元12H放高字节,34H放低字节,后一单元同样)
(2)字符串表达式:每一个字符占一个字节单元。
1)使用DB:字符串不超过255个字符,大尾方式存放。eg:VA DB ‘ABCDEF‘ (从’A‘至‘F‘按地址递增排列)
2)使用DW:最多为两个字符组成的字符串分配存储单元,小尾方式存放。eg:VA DW ‘AB‘,‘CD‘,‘EF‘ (地址递增排序为:‘BADCFE‘)
3)使用DD:最多为两个字符组成的字符串分配存储单元,小尾方式存放,且第2个字单元存放0000H。eg:VA DD ‘AB‘,‘CD‘ (地址递增排序为:‘B‘‘A‘‘00‘‘00‘‘D‘‘C‘‘00‘‘00‘)
(3)?表达式:预置随机值。eg:VA DB ?,?
(4)地址表达式:若该地址表达式为一变量名或者标号名,那么DW定义则是用其偏移量预置;DD定义则是用其段基值和偏移量预置,且段基值存高字单元,偏移量存低字单元。eg:VB DD VA (VB的高字单元存放VA的段基值,低字单元存VA的偏移量)
(5)带DUP的表达式:格式:变量名 伪指令 n DUP(表达式) 功能:定义重复数据。
eg:VA DW 10H DUP(4) (即分配了10H个字单元,都每个字单元预置4) VB DB 10H DUP(‘ABCD‘) (分配了10H个字符串’ABCD‘,共10H*4=40H个字节)
DUP可以嵌套使用。
eg:VA DB 10H DUP(4 DUP(2),3,4)等价于 VA DB 10H DUP(2,2,2,2,3,4)
(6)混合使用:eg:VA DB 2 DUP(1),2 DUP(2,‘B‘),‘123‘,1,2
十一、标号:
1.属性:
(1)SEG:所在段的段基值;
(2)OFFSET:距离段基址的字节数(偏移量);
(3)类型属性Distance:NEAR、FAR。
2.类型属性设置:
(1)缺省默认NEAR。
(2)LABEL伪指令方式:建立新的标号并赋予指定类型属性。
eg:J1 LABEL FAR
J2: MOV AX,20H
两个标号J1和J2指向同一个地方,但类型属性不同。
十二、运算符:
1.算术运算符:+、-、*、/、MOD、[]。
2.移位运算符:SHR(右移),SHL(左移) eg:MOV AX,11011011B SHL 3等价于MOV AX,1101011000B
3.逻辑运算符:NOT、AND、OR、XOR eg:MOV AX,NOT 0F0H
4.关系运算符:EQ(相等为真A=B)、NE(不相等为真A!=B)、LT(A<B)、LE(A<=B)、GT(A>B)、GE(A>=B)。表达式都是常数或者同段的偏移量。如果是常数,按照无符号数比较;如果是变量,比较其偏移量。比较结果以真(全1)或假(全0)给出。 eg:MOV AX,0FH EQ 1111B等价于MOV AX,0FFFFH
5.数值返回运算符:
(1)SEG:返回变量或者标号的段基值。 eg:MOV AX,SEG VA
(2)OFFSET:返回变量或标号的偏移量。eg:MOV AX,OFFSET VA
(3)TYPE:返回变量或标号的类型属性的数字形式:变量(BYTE(1)、WORD(2)、DWORD(4))、标号(NEAR(-1)、FAR(-2)) eg:MOV AX,TYPE VA
(4)LENGTH:仅用于变量之前,返回数组变量的元素个数。如果变量包含DUP,那么返回其重复值n;否则,返回1。 eg:MOV AX,LENGTH VA
(5)SIZE:仅用于变量之前,返回数组变量所占的总字节数,即等价于LENGTH与TYPE的乘积。 eg:MOV AX,SIZE VA
6.属性修改运算符:
(1)PTR:格式:类型 PTR 地址表达式 其中,地址表达式是指要修改或指定类型属性的标号、变量或用做地址指针的寄存器。不过,此修改仅在PTR语句里生效,临时修改而已。 eg:MOV AX,WORD PTR DATA_BYTE[10] MOV WORD PTR [SI],30H
(2)HIGH和LOW:只放在一个常数或在能确定其段基值或偏移量的地址表达式前面,用来分离运算对象的高字节和低字节。
eg:CONST EQU 0ABCDH
MOV AH,HIGH CONST
eg2:MOV BH,HIGH(SEG DA1)
十三、伪指令:
1.EQU:等值伪指令:格式:符号名 EQU 表达式 其中,表达式可以是常数、数值表达式、字符串、地址表达式、标号、变量、指令助记符或关键字等。
eg:CONT EQU 5 ADR EQU ES:10H[BX] VA EQU AX VA EQU ADD。
不能重复定义,除非解除原先定义。
PURGE:用来解除EQU的定义。eg:PURGE CONT,ADR 注意:不能用PURGE解除被PUBLIC说明的符号的定义
2.=:格式:符号名=表达式。eg:CONT=5
与EQU的区别:(1)=允许重复定义;(2)=后的表达式不能是指令助记符或关键字。
3.DB(字节变量)、DW(字变量)、DD(双字变量)、DQ(四字变量)、DT(五字变量)
4.LABEL:与PTR功能相同,并且作用不受限制。
(1)改变标号属性:见前面的(十一.2.(2))。
(2)改变变量属性:
eg:VA LABEL BYTE
VB DW 20H DUP(0)
VA与VB段基值、偏移量都相同,但类型不相同。
5.段定义伪指令
格式:段名 SEGMENT [定位类型][组合类型][类别名]
......
段名 ENDS
6.ASSUME:段寻址伪指令,指定逻辑段与段寄存器之间的关系。eg:ASSUME CS:CODE,DS:DATA
注意:(1)该指令不产生机器码。
(2)若不指定,程序中使用变量名或地址表达式时要加上段前缀。eg:MOV AX,ES:VA
(3)该指令也可以取消或修改指定关系。
eg:ASSUME ES:NOTHING ;删除对ES的关联 ASSUME NOTHING ;删除所有关联
7.PROC/ENDP:过程定义伪指令。
格式:过程名 PROC [NEAR/FAR]
......
RET
......
过程名 ENDP
8.ORG/$:定位伪指令和当前位置计数器。
eg:ORG 30H;该语句之后的指令或数据以当前值30H作为起始偏移量。 eg:ORG $+20H ;$即当前位置计数器
9.TITLE:标题伪指令。格式:TITLE 标题名
10.END:程序结束伪指令。格式:END 起始地址 功能:一方面表示什么时候结束程序,一方面指定程序装入内存时根据起始地址对CS和IP装入对应的段基值和偏移量。
11.PUBLIC/EXTRN:前者用来定义全局符号,后者用来标明当前模块中要访问的本模块之外的符号。
十四、源程序中段寄存器的装入以及DOS返回:
1.DS和ES的装入:
DS:MOV AX,DATA MOV DS,AX
ES:MOV AX,DATA2 MOV ES,AX
2.SS的装入:
(1)系统自动装入:在定义堆栈逻辑段时,指定其组合类型为STACK,并在ASSUME中关联。eg:STACK1 SEGMENT STACK ........
(2)手动法:
1 STACK1 SEGMENT 2 DW 20H DUP(?) 3 TOP LABEL WORD 4 STACK1 ENDS 5 6 CODE SEGMENT 7 ...... 8 MOV AX,STACK1 9 MOV SS,AX 10 MOV SP,OFFSET TOP 11 .......
3.CS的装入:
一般方法:程序结束伪指令END直接搞定,装入CS和IP。格式:END 起始地址
4.DOS返回:
(1)用4CH系统功能调用实现返回:即在程序结束时加上:MOV AH,4CH INT 21H
(2)用程序段前缀实现返回:三步:1)把程序编制成一个过程,设置为FAR。2)把PSP起始地址压栈。3)程序结束时RET。
1 CODE SEGMENT 2 PROC1 PROC FAR 3 ASSUME CS:CODE,... 4 START: PUSH DS ;保存PSP首地址,RET返回时将其装入CS 5 MOV AX,0 6 PUSH AX ;RET返回时把00H作为偏移量装入IP 7 ... 8 RET 9 PROC1 ENDP 10 CODE ENDS 11 END START
十五、分支程序设计:
1.无条件转移指令JMP:不影响FLAGS。
(1)段内转移:只需要修改IP值。
1)直接寻址:JMP TARGET (TARGET为标号) 指令编码2~3字节。
2)间接寻址:JMP REG或者JMP ADDR (REG为寄存器,ADDR为字存储单元,存储着目标地址) 指令编程2~4字节
eg:JMP CX; JMP WORD PTR [BX]; JMP VA;
(2)段间转移:需要修改CS和IP值。
1)直接寻址:JMP TARGET 指令编码5字节。
2)间接寻址:JMP ADDR (ADDR为双字存储单元,存储目标地址) 指令编码2~4字节 eg:JMP DWORD PTR VA[BX]
2.条件转移指令:格式:JXX TARGET (TARGET为标号) 执行的操作:IP<=TARGET的偏移量 指令编码都是2字节。
该系列指令只能在段内直接寻址,并且转移范围在从下一条指令算起的-128~127个字节的地址范围内。且不影响FLAGS。
(1)简单条件转移指令:
JC CF=1 有进位/借位
JNC CF=0 无进位/借位
JE/JZ ZF=1 相等/等于0
JNE/JNZ ZF=0 不相等/不等于0
JS SF=1 为负数
JNS SF=0 为正数
JO OF=1 有溢出
JNO OF=0 无溢出
JP/JPE PF=1 有偶数个1
JNP/JPO PF=0 有奇数个1
(2)无符号数条件转移指令:假设此指令前进行无符号数A、B的比较,指令的操作为A-B
JA/JNBE CF=0&&ZF=0 A>B
JAE/JNB CF=0||ZF=1 A>=B
JB/JNAE CF=1&&ZF=0 A<B
JBE/JNA CF=1||ZF=1 A<=B
(3)有符号数条件转移指令:假设此指令前进行有符号数A、B的比较,指令的操作为A-B
JG/JNLE SF=OF&&ZF=0 A>B
JGE/JNL SF=OF||ZF=1 A>=B
JL/JNGE SF!=OF&&ZF=0 A<B
JLE/JNG SF!=OF||ZF=1 A<=B
3.对于多路分支,可以使用跳转表法。
(1)跳转表由入口地址构成:
1 DATA SEGMENT 2 ATABLE DW V1,V2 3 DW V3,V4 4 N DB 3 5 Y DW 0F786H 6 DATA ENDS 7 STACK1 SEGMENT STACK 8 DW 20H DUP(?) 9 STACK1 ENDS 10 CODE SEGMENT 11 ASSUME CS:CODE,DS:DATA,SS:STACK1 12 START: MOV AX,DATA 13 MOV DS,AX 14 MOV BX,OFFSET ATABLE 15 XOR AH,AH 16 MOV AL,N 17 DEC AL 18 SHL AL,1 19 ADD BX,AX 20 JMP WORD PTR [BX] 21 V1: 22 ADD Y,100 23 JMP DONE 24 V2: 25 ADD Y,99 26 JMP DONE 27 V3: 28 ADD Y,98 29 JMP DONE 30 V4: 31 ADD Y,97 32 JMP DONE 33 DONE: MOV AH,4CH 34 INT 21H 35 CODE ENDS 36 END START 37
(2)跳转表由JMP指令构成:
1 DATA SEGMENT 2 N DB 3 3 Y DW 0F786H 4 DATA ENDS 5 STACK1 SEGMENT STACK 6 DW 20H DUP(?) 7 STACK1 ENDS 8 CODE SEGMENT 9 ASSUME CS:CODE,DS:DATA,SS:STACK1 10 START: MOV AX,DATA 11 MOV DS,AX 12 MOV CX,OFFSET ATABLE 13 XOR BH,BH 14 MOV BL,N 15 DEC BL 16 MOV AL,BL 17 SHL BL,1 18 ADD BX,CX 19 JMP BX 20 ATABLE: 21 JMP V1 22 JMP V2 23 JMP V3 24 JMP V4 25 V1: 26 ADD Y,100 27 JMP DONE 28 V2: 29 ADD Y,99 30 JMP DONE 31 V3: 32 ADD Y,98 33 JMP DONE 34 V4: 35 ADD Y,97 36 JMP DONE 37 DONE: MOV AH,4CH 38 INT 21H 39 CODE ENDS 40 END START 41
十六、循环程序设计:
循环控制指令:使用CX作为计数器,采用段内直接寻址,操作数为标号,不影响FLAGS。格式都是:LOOP TARGET。指令编码2字节。并且转移范围在从下一条指令算起的-128~127个字节的地址范围内。
LOOP: 首先CX<=CX-1。如果CX!=0,则IP<=TARGET的偏移量;否则,顺序执行。
LOOPZ/LOOPE:首先CX<=CX-1。如果CX!=0&&ZF=1,则IP<=TARGET的偏移量;否则,顺序执行。
LOOPNZ/LOOPNE:首先CX<=CX-1。如果CX!=0&&ZF!=1,则IP<=TARGET的偏移量;否则,顺序执行。
JCXZ: 测试CX==0,但不修改其值。如果CX=0,则IP<=TARGET的偏移量;否则,顺序执行。
十七、子程序设计:
1.子程序定义格式:
过程名 PROC [NEAR/FAR]
......
RET
......
过程名 ENDP
2.段内调用:
(1)直接调用:CALL PROC_NAME(过程名) 指令操作:将IP压栈,IP<=子程序入口偏移量 指令编码3字节
(2)间接调用:CALL REG或者CALL W_ADDR (操作数为通用寄存器或者变量、标号) 指令操作:将IP压栈,IP<=REG/W_ADDR. 指令编码2~4字节
3.段间调用:
(1)直接调用:CALL PROC_NAME(FAR属性) 指令操作:依次将CS、IP压栈,CS<=子程序段基值,IP<=子程序偏移量。 指令编码5字节。
(2)间接调用:CALL DW_ADDR (操作数为变量或标号) 指令操作:依次将CS、IP压栈,IP<=第一个字存储单元内容,CS<=第二个字存储单元内容。 指令编码2~4字节。
4.返回指令RET:
(1)段内返回:RET 或 RET n(n为偶数)。 指令操作:对IP出栈。如果带有n,则SP<=SP+n。 不带操作数时编码为C3,单字节;带操作数时3字节。
(2)段间返回:RET 或 RET n(n为偶数)。 指令操作:先对IP出栈,再对CS出栈。如果带有n,则SP<=SP+n。 不带操作数时编码为CB,单字节;带操作数时3字节。
其中,RET n的作用是将call指令前压栈的参数数据占据的空间释放。
5.子程序与主程序之间的参数传递可以通过寄存器、堆栈或者地址表实现。这里不表。
十八、乘除法运算:
1.无符号数乘法MUL:MUL OPRD 只影响FLAGS中的CF和OF。若乘积的高半部分不为0,则CF=OF=1;否则,CF=OF=0。其他标志位不确定。
字节乘法:AX=AL*OPRD 乘积放入AX中。
字乘法: DX:AX=AX*OPRD 乘积的高字放入DX,低字放入AX。
2.带符号数乘法IMUL:IMUL OPRD 只影响FLAGS中的CF和OF。如果乘积的高半部分不是低半部分的符号扩展,则CF=OF=1;否则,CF=OF=0。其他标志位不确定。
字节乘法:AX=AL*OPRD 乘积放入AX中。
字乘法: DX:AX=AX*OPRD 乘积的高字放入DX,低字放入AX。
3.无符号数除法DIV:DIV OPRD 不影响FLAGS。
字节除法:被除数AX 除数OPRD 商AL 余数AH
字除法: 被除数DX:AX除数OPRD 商AX 余数DX
如果除数为0或者商AL>0FFH或者AL>0FFFFH,转入0型中断。
4.带符号数除法IDIV:IDIV OPRD 不影响FLAGS。
字节除法:被除数AX 除数OPRD 商AL 余数AH
字除法: 被除数DX:AX除数OPRD 商AX 余数DX
如果除数为0或者商AL>7FH或者AL>7FFFH,转入0型中断。
实验部分:可以参考http://wenku.baidu.com/view/8d9f9aef0975f46527d3e10b.html。