第1章 基础知识
其中提到了二进制数、八进制数和十六进制数的相互转换,补码,反码,逻辑运算的知识。这些知识我们都在数字逻辑这门课里学到过,在这里就不赘述了。
- *
第2章 80x86计算机组织
寄存器组
通用寄存器
通用寄存器都可以以字(16位)或者字节(8位)的形式访问。
- AX(accumulator)
主要作为累加器使用,它是算术运算的主要寄存器。另外,所有的I/O指令都使用这一寄存器与外部设备传送信息。(例如我们要在屏幕上输出一个字符的时候,我们就要把输出字符的指令02H放在AL寄存器中)
- BX(base)
可以作为通用寄存器使用。此外在计算存储器地址时,它经常用作基址寄存器。
- CX(count)
可以作为通用寄存器使用。此外常用来保存计数值。(例如在LOOP时,每循环一次CX就要减一,还有在移位操作时,如果移动的位数不是1位,就要将移动的次数保存在CX寄存器中)。
- DX(data)
可以作为通用寄存器使用。一般在作双字运算时把DX和AX组合在一起存放一个双字长数,DX用来保存高位字。此外,对某些I/O操作,DX可用来存放I/O的端口地址。(例如我们要在屏幕上输出一个字符的时候,就要将所输出的字符放在DL中,输出字符串的时候,就要把字符串的偏移地址放在DX中)。
- SI&DI
分别为源变址寄存器和目的变址寄存器,均只能以16位为单位使用。
一般与数据段寄存器DS联用,用来确定数据段中某一存储单元的地址。
这两个变址寄存器有自动增量和自动减量的功能,用于变址很方便。
串处理指令中,SI和DI作为隐含的源变址和目的变址寄存器,此时SI和DS联用,DI和附加段寄存器ES联用,分别达到在数据段和附加段中寻址的目的。
AL与AH、BL与BH、CL与CH、DL与DH分别对应于AX、BX、CX和DX的低8位与高8位。
AX、BX、CX、DX、SI、DI、BP和SP分别对应于EAX、EBX、ECX、EDX、ESI、EDI、EBP和ESP的低16位。
专用寄存器
- IP(instruction pointer)
作为指令指针寄存器,它用来存放代码段中的偏移地址。在程序的运行的过程中,它始终指向下一条指令的首地址,它与段寄存器CS联用确定下一条指令的物理地址。
- SP
作为堆栈寄存器,它用来存放栈顶的偏移偏移地址。(注意:栈顶指针在有数据入栈的时候,会减小,有数据出栈的时候,会增加)
- FLAGS
称为标志寄存器,这是一个存放条件码、控制标志和系统标志的寄存器。其中有几个比较重要的标志位需要记忆。
- CF(carry flag)进位标志。它记录了从最高有效位产生的进位值,减法运算时是借位,以及循环移位时。当最高有效位有进位时为1,否则为0。
- PF(parity flag)奇偶标志。当操作数中1的个数为偶数时为1,否则为0。
- ZF(zero flag)零标志。当运算结果为0时为1,否则为0。
- SF(sign flag)符号标志。记录了运算结果的符号,结果为负时为1,否则为0。
- OF(overflow flag)溢出标志。当操作数超出了机器能表示的范围时为1,否则为0。
- DL(direction flag)控制标志位为方向标志。主要在串处理时使用,当DF为1时,每次操作之后都会使变址寄存器SI、DI减小,从而从高地址向低地址处理。反之,当DF为0时,每次操作后会使SI、DI变大。
- IF(interrupt flag)中断标志。当IF为1时,可允许CPU响应可屏蔽中断请求,否则关闭请求,这在第8章中会涉及到。
段寄存器
段寄存器也是一种专用寄存器,它们主要用来存储器寻址,用来直接或间接的存放段地址。常见的有代码段(code segment)、数据段(data segment)、堆栈段(stack segment)和附加段(extra segment)。
其中FS、GS以及所有32位寄存器是从80386 CPU开始引入的。他们也是属于附加的数据段。
存储器
存储器的信息是以字节为单位的,每一个字节单元只有一个惟一的存储器地址,称为物理地址。
一个存储单元中存放的信息称为该存储单元的内容。
对于字节数据而言,数据在内存中连续存放,对于字数据而言,要占有两个字节,则存放时低位字节存入低地址,高位字节存入高地址。例如1234H,在内存中存储为34 12,因为内存中低地址靠前(左),高地址靠后(右)。
例如上图,字节12340H、12341H的内容分别为:12H和34H;字12340H、12341H的内容分别为:3412H和5634H;双字12340H、12341H的内容分别为:78563412H和90785634H。
物理地址与逻辑地址
物理地址:内存单元的实际地址,也就是出现在地址总线上的地址。
逻辑地址:或称分段地址,记作 段地址: 段内偏移地址。
有效地址:将存储单元的实际地址与其所在段的段地址之间的距离称为段内偏移量(EA,Effective Address 或Offset)。
系统采用下列方法将逻辑地址自动转换为20位的物理地址:物理地址 = 段地址 × 16 + 偏移地址
实模式存储器寻址
实模式下允许最大寻址空间为1MB,因为8086的地址总线宽度为20位,则$2^{20}=1024K=1M$,所以最大寻址空间为1MB。
(20位物理地址由16位段地址和16位偏移地址组成,段地址是指每一段的起始地址,由于它必须是小段的首地址,所以其低4位一定时0,这样,就可以规定段地址只取段起始地址的高16位值)。括号里的不想看,简而言之就是下图的计算方法,上面也提到了。
也就是说,把段地址左移4位加上偏移地址就形成了物理地址。(一般给出的地址都是16进制的形式,这里的4位是指2进制的4位,所以对于16进制而言,只需要段地址后加一个0,一个0相当于二进制的0000,也就是向左移4位)。
物理地址 = 段地址 × 16 + 偏移地址
物理地址 = 段地址 × 16 + 偏移地址
物理地址 = 段地址 × 16 + 偏移地址
重要的事情说三遍!!!
- *
第3章 80x86的指令系统和寻址方式
寻址方式
基本的寻址方式有七种,含比例因子的变址寻址方式有三种,我们来一一回顾。
立即寻址
MOV AH, 80H
MOV ECX, 12345678H
MOV AX, 4576H
以上这些都是立即寻址,因为他们的第二操作数都是立即数,所以立即寻址的名字也就是这么来的,很好记忆。
注意:以上指令中立即数不能作为第一操作数。而且源操作数和目的操作数的长度要一致。立即数可以是8位或者是16位的,在386+的机型中,立即数可以是8位或者32位的。
寄存器寻址
MOV EAX, EBX
ADD AX, DX
ADD AX, 1234H
这种寻址方式由于操作数就在寄存器当中,不需要访问存储器来取得操作数,因而可以得到较高的运算速度。前两个例子与立即寻址的长相不同,一看是寄存器作为第二操作数,那肯定就是寄存器寻址了,为什么第三个例子也是寄存器寻址呢?
因为第三个例子中AX这个寄存器本来就是有值的,这个指令的含义就是将AX中的内容加1234H得到的结果再放到AX中,那么在第一步获取AX的值的时候就采用了寄存器寻址的方式。
直接寻址
MOV BX, [1234H] ;缺省使用段寄存器DS
MOV ES:[1000H], AX ;指定用段寄存器ES
操作数的有效地址只包含 位移量这一种成分,其值就存放在代码段中指令的操作码之后。位移量的值即操作数的有效地址。在汇编语言中,可以使用符号地址代替数值地址,例如MOV AX, VALUE
,此时的VALUE是存放操作数单元的符号地址,写成MOV AX, [VALUE]
也是可以的,二者是等效的。
值得一提的是,在第二个例子中,[1000H]
在附加段中,则加上指定段的跨越前缀,在此处为ES:
,如不写出,缺省为DS:
。
寄存器间接寻址
MOV BX, [DI]
MOV AX, [BX]
操作数的有效地址只包含基址寄存器内容或变址寄存器内容的一种成分。
例如第一个例子中,DI
为变址寄存器,变址寄存器有SI
和DI
两种,而基址寄存器有BX
和BP
两种,就展现在第二个例子中。
注意:若有效地址用SI
、DI
和BX
等之一来指定,则其缺省的段寄存器为DS
。若有效地址用BP
来指定,则其缺省的段寄存器为SS
(即:堆栈段)。
寄存器相对寻址(或称直接变址寻址)
MOV EAX,TABLE[ESI]
MOV AX, COUNT[SI]
;(也可表示成MOV AX,[COUNT+SI])
;其中COUNT为16位位移量的符号地址
操作数的有效地址为基址寄存器或变址寄存器的内容和指令中指定的位移量之和。所以有效地址由两种成分,一个是基址寄存器或变址寄存器的内容,另一个是指定的位移量。举个例子,如果(DS)=3000H,(SI)=2000H,COUNT=3000H,则物理地址=3000*16+2000+3000=30000+2000+3000=35000H
对于寄存器间接寻址和寄存器相对寻址两种方式来说,在名称上只有“相对”和“间接”的区别,但还是很好区分的:“间接”表示通过一个寄存器间接寻址,重点是“一个寄存器”,而“相对”的意思就是相对一个寄存器还要偏移一部分的方式,重点是“相对着一个有另一个”,那么就是两个寄存器,这样就很好区分寄存器间接寻址和寄存器相对寻址了。
基址变址寻址
MOV AX, [BX][DI]
;或写为:MOV AX,[BX+DI]
操作数的有效地址是一个基址寄存器和一个变址寄存器的内容之和。
简单来说,就是只能用一个基址寄存器和一个变址寄存器,而且是必须!
如(DS)=2100H,(BX)=0158H,(DI)=10A5H,则EA=0158+10A5=11FDH,则物理地址=21000+11FD=221FDH。
基址变址寻址同样很好记忆,因为这种寻址方式的名字就叫做基址变址,所以需要一个基址寄存器和一个变址寄存器。
相对基址变址寻址
MOV AX, [BX+SI+200H]
;或写成:MOV AX, 200H[BX][SI]
操作数的有效地址是一个基址寄存器与一个变址寄存器的内容和指令中指定的位移量之和,所以有效地址由三部分组成。例如当(DS)=3000H,(BX)=2000H,(SI)=1000H,MASK=0250H。则物理地址=16D*(DS)+(BX)+(SI)+MASK=30000+2000+1000+0250=33250H
这种寻址方式的名字就叫做相对基址变址,所以需要一个基址寄存器和一个变址寄存器,又有“相对”这个字眼,那么就需要出现一个偏移量作为相对的量,那么看到名字就可以知道这个寻址方式需要三个寄存器。
含比例因子的变址寻址
在这里我们就不详细介绍这三种寻址方式了,因为他们都是在386+的机型里才有的,我们只需要知道名称,他们分别是比例变址寻址方式、基址比例变址寻址方式、相对基址比例变址寻址方式。
对于寻址方式就回顾到这里,在后面的综合应用中还是要牢记这七种基本的寻址方式。
80x86的指令系统
指令系统是一个重要的系统,因为它涉及到整个汇编语言的编写,而且这里的指令就是一个助记符,它代表的就是机器指令,在80x86的机型中,我们将指令分为这么6组:数据传送指令、算术指令、逻辑指令、串处理指令、控制转移指令、处理机控制指令。下面我们就来总览一下这些考试中常见以及常用的指令。
数据传送指令
通用数据传送指令
MOV 传送
PUSH 进栈
POP 出栈
XCHG 交换
- MOV(move)传送
格式是:MOV DST,SRC
它的含义就是将SRC
中的内容复制到DST
中去,SRC
不变。对标志位无影响。
注意MOV指令的使用规范,不能有以下操作:
(1) 两个操作数类型不一致:如字节和字不一致
(2) 两个操作数不能都是存储器,如:MOV [BX], [SI]
(3) 将立即数传送给段寄存器,如:MOV DS, 100H
(4) 不能直接改变CS
的值,如:MOV CS, [SI]
(5) 段寄存器间不能进行直接的数据传送,如:MOV DS, ES
,要传送段地址必须通过寄存器(如AX
寄存器)送到DS
寄存器
(6) IP
不能作为MOV
的操作数
- PUSH 进栈
格式是:PUSH SRC
含义就是将SRC
进行压栈操作,这个操作可以用来进行保存现场,简单来说就是可以将SRC
的值临时保存在栈中,在POP
操作后可以将这个临时保存的值取出来。该操作对标志位无影响。
要注意的是:PUSH
操作只能对字数据以及双字数据进行操作。当对16位操作数进行操作时,SP = SP-2
,SS:[SP]
指向16位操作数;当对32位数据进行操作时,SP = SP-4
,SS:[SP]
指向32位操作数。 PUSH
指令可以有的四种格式:
PUSH reg(寄存器)
PUSH mem(存储器)
PUSH data(立即数)
PUSH segreg(段寄存器)
- POP 出栈
格式是:POP DST
它的含义就是将堆栈中的值取出来,赋值给DST
。同样,POP
操作也只能对16位和32位数据进行操作。它也对标志位无影响。
要注意的是:当对16位操作数进行操作时,16位操作数←SS:[SP]
,SP = SP + 2
;当对32位操作数进行操作时,32位操作数←SS:[SP]
,SP = SP + 4
。
要记住,堆栈这个数据结构,其栈底的地址较高,栈顶的额地址较低,所以展现出在有数据压栈的时候SP
是进行减操作的,而当有数据进行出栈操作的时候,SP
指针的进行加操作的。所以越靠近栈底的地址越大。 POP
指令允许的格式有:
POP reg(寄存器)
POP mem(存储器)
POP segreg(段寄存器)
- XCHG(exchange)交换
格式是:XCHG OPR1, OPR2
其含义就是将OPR1
与OPR2
两个操作数的内容进行交换。
要注意的是:该指令的两个操作数中必须有一个在寄存器中,因此它可以在寄存器之间或者在寄存器与存储器之间交换信息,但不允许段寄存器。该指令可用除立即数外的任何寻址方式,且不影响标志位。
累加器专用传送指令
这组指令只限于使用累加器EAX
、AX
或AL
传送信息。
IN 输入
OUT 输出
XLAT 换码
- IN(input)输入
长格式为:
IN AL, PORT(字节)
IN AX, PORT(字)
IN EAX, PORT(双字)
短格式为:
IN AL, DX(字节)
IN AX, DX(字)
IN EAX, DX(双字)
该指令的作用是从端口中读入一个字节或字或双字,并保存在寄存器AL
或AX
或EAX
中。如果某输入设备的端口地址在0~255范围之内,可在指令中直接给出PortNo,否则要把该端口地址先存入寄存器DX
中。
例:
IN AL, 20H ;从端口20读入1个字节的内容,传送到累加器AL
IN AL, DX ;DX需预先赋值,从指定端口传送一个字节到AL
- OUT(output)输出
长格式为:
OUT PORT, AL(字节)
OUT PORT, AX(字)
OUT PORT, EAX(双字)
短格式为:
OUT DX, AL(字节)
OUT DX, AX(字)
OUT DX, EAX(双字)
把寄存器AL
或AX
或EAX
的内容输出到指定端口。
这里注意一下,长格式指的是外设的前256个端口,当端口号大于等于256时,只能使用短格式,此时必须先把端口号放到DX
寄存器中,然后再用IN
或者OUT
来传送信息。
- XLAT(Translate)换码
一般格式为:XLAT OPR
它的作用就是将DS:BX
所指内存区中、由AL指定位移处的一个字节赋值给AL。而且它对标志位无影响。它可以用于加密,也可用于数码管显示数字。
例:
地址传送指令
这里就复习一下LEA
和LDS
就行辣...
- LEA(load effective address)有效地址送寄存器
一般格式为:LEA REG, SRC
功能:把一个内存变量的有效地址送给指定的寄存器(此处reg不能使用段寄存器)。当reg长度大于地址长度时,将地址零扩展后存入reg;当reg长度小于地址长度时,截取地址的低16位存入reg。该指令通常用来对指针或变址寄存器BX
、DI
或SI
等置初值之用。对标志位无影响。
简单来说,该指令就是把源操作数的有效地址送到指定的寄存器中。(注:此处的有效地址不是物理地址,不用加DS)
例:
设BX=5678H,EAX=00002345H,EDX=00001111H。
LEA SI, 2[BX] ;执行后,SI = 567AH
LEA SI, 2[EAX][EDX] ;执行后,SI = 3458H,因为SI是一个16位的寄存器
- LDS(load DS with pointer)指针送寄存器和DS
一般格式为:LDS REG, SRC
功能:当指令指定的是16位寄存器时,把该存储单元中存放的16位偏移地址(即SRC
)装入该寄存器中,然后把SRC+2
中的额16位数装入DS
中。该指令不影响标志位。(当指令指定的是32位寄存器时,把该寄存单元中存放的32位偏移地址装入该寄存器中,然后把SRC+4
中的16位数装入指令指定的段寄存器中)
标志寄存器传送指令
共有四条与标志寄存器相关的指令。
LAHF 标志寄存器送累加器指令
SAHF 累加器送标志寄存器指令
PUSHF/PUSHFD 标志进栈
POPF/POPFD 标志出栈
- LAHF(load AH with flags)标志寄存器送累加器指令
一般格式:LAHF
功能:将标志寄存器的低8位传送到AH
中。该指令对标志位无影响。
- SAHF(store AH into flags)累加器送标志寄存器指令
一般格式为:SAHF
功能:将AH
的值传送给标志寄存器的低8位。该指令对标志位的影响由新装入标志寄存器的值决定。
- PUSHF/PUSHFD(push the flags or eflags)标志进栈
一般格式为:PUSHF
或PUSHFD
功能:将FLAGS
进栈,并且SP = SP - 2
/将EFLAGS
进栈,并且SP = SP - 4
。对标志位的影响:PUSHFD
清除VM
和RF
位。
- POPF/POPFD(pop fkags off stack)标志出栈
一般格式为:POPF
或POPFD
功能:将栈顶字出栈到FLAGS
, 并且SP = SP + 2
/将栈顶双字出栈到EFLAGS
,并且SP = SP + 4
。对标志位的影响:POPF/POPFD
指令会以弹出值设置标志寄存器。
类型转换指令
这里只强调这两个指令:
CBW 字节转换为字
CWD 字转换为双字
- CBW(convert byte to word)字节转换为字
一般格式为:CBW
功能:将AL
的内容符号扩展到AH
,形成AX
中的字。如果AL
的最高有效位为0,则AH=0
;如果AL的最高有效位为1,则AH=0FFH
。
注意:这个指令进行的是符号位扩展。还有一点就是它只针对AX
,没有其他的寄存器。
- CWD(convert word to double word)字转换为双字
一般格式为:CWD
功能:将AX
的内容符号扩展到DX
,形成DX:AX
中的双字。即如果AX
的最高有效位为0,则DX=0
;如AX
的最高有效位为1,则DX=0FFFFH
。
注意:同CBW
类似,它进行的是符号位的扩展,而且它只扩展到DX
,没有其他的寄存。
算术指令
加法指令
ADD 加法
ADC 带进位加法
INC 加1
- ADD(add)加法
一般格式:ADD DST, SRC
功能:把源操作数的值加到目的操作数中。
受影响的标志位:CF
、PF
、AF
、ZF
、SF
和OF
。
注意:如前所述,双操作数的指令的两个操作数中除源操作数为立即数的情况外,必须有一个操作数在寄存器中。单操作数指令不允许使用立即数的方式。
- ADC(add with carry)带进位的加法
一般格式:ADC DST, SRC
功能:把源操作数和进位标志CF
的值一起加到目的操作数中。
受影响的标志位:CF
、PF
、AF
、ZF
、SF
和OF
。
注意点和ADD
相同。
- INC(increment)加1
一般格式:INC OPR
功能:把操作数的值加1再存入该操作数中。
受影响的标志位:PF
、AF
、ZF
、SF
和OF
,但不影响CF
。
为实现双精度加法,必须用两条指令分别完成低位字和高位字的加法,而且在高位字相加时,应使用ADC
指令,以便把前一条ADD
指令作为低字加法所产生的进位值加入高位字之内。
减法指令
SUB 减法
SBB 带借位减法
DEC 减1
NEG 求补
CMP 比较
- SUB(subtract)减法
一般格式:SUB DST, SRC
功能:从目的操作数中减去源操作数,把差值赋值给目的操作数。
受影响标志位:CF
、PF
、AF
、ZF
、SF
和OF
。
- SBB(subtract with borrow)带借位减法
一般格式:SBB DST, SRC
功能:把源操作数和标志位CF
的值从目的操作数中一起减去,把差值赋给目的操作数DST
。
受影响标志位:CF
、PF
、AF
、ZF
、SF
和OF
。
- DEC(decrement)减1
一般格式:DEC OPR
功能:把操作数的值减1把结果存入该操作数中。
受影响的标志位:PF
、AF
、ZF
、SF
和OF
,但不影响CF
。
- NEG(negate)求补
一般格式:NEG OPR
功能:操作数=0-操作数,即改变操作数的正负号。
受影响标志位:CF
、PF
、AF
、ZF
、SF
和OF
。
- CMP(compare)比较
一般格式:CMP OPR1, OPR2
功能:用第一个操作数减去第二个操作数,并根据所得的差值设置有关的标志位。但它与SUB
的区别就是不会将减法的结果保存在OPR1
中。
受影响标志位:CF
、PF
、AF
、ZF
、SF
和OF
。
乘法指令
MUL 无符号数乘法
IMUL 带符号数乘法
- MUL(unsigned multiple)无符号数乘法
一般格式:MUL SRC
功能:把显式操作数和隐含操作数(都作为无符号数)相乘,所得的乘积如表中对应关系存放。
乘数位数 | 隐含的被乘数 | 指令举例 | 乘积的存放位置 |
---|---|---|---|
8位 | AL | MUL BL,IMUL BL | AX ←AL *BL |
16位 | AX | MUL BX,IMUL BX | DX-AX ←AX *BX |
32位 | EAX | MUL ECX,IMUL ECX | EDX-EAX ←EAX *ECX |
- IMUL(signed multiple)带符号数乘法
一般格式:IMUL SRC
功能:与MUL
相同,但必须是带符号数,而MUL
是无符号数。
除法指令
DIV 无符号数除法
IDIV 带符号数除法
- DIV(unsigned divide)无符号数除法
一般格式:DIV SRC
功能:用显式操作数去除隐含操作数(都作为无符号数),所得商和余数如表所示存放。指令对标志位的影响无定义。
除数位数 | 隐含的被除数 | 商 | 余数 | 指令举例 |
---|---|---|---|---|
8位 | AX | AL | AH | DIV BH,IDIV NUM1 |
16位 | DX-AX | AX | DX | DIV BX,IDIV [BX] |
32位 | EDX-EAX | EAX | EDX | DIV ECX,IDIV EBX |
这里注意一个问题:以8位除数举例,当被除数为一个很大的数,如EFFFH,除数是一个很小的数,如1H,那么按理来说得到的商应该是EFFFH,应该存在AL
中,但是EFFFH是一个16位的数,而AL
最多能存8位的数,商就会溢出,那这该怎么办呢?在实际的编译环境中实验上述的问题,得到结果是divide error。说明对于这样的被除数和除数是不能参加除法运算的,为了保证能进行运算,有以下的规定:
1)字节操作时,被除数的高8位绝对值<除数的绝对值;
2)字操作时,被除数的高16位绝对值<除数的绝对值;
3)双字操作时,被除数的高32位绝对值<除数的绝对值。
- IDIV(signed divide)带符号数除法
一般格式:IDIV SRC
功能:与DIV
相同,但必须是带符号数,而IDIV
是无符号数。
十进制调整指令
DAA 加法的十进制调整指令
DAS 减法的十进制调整指令
AAM 乘法的ASCII调整指令
AAD 除法的ASCII调整指令
- DAA(decimal adjust for addition)加法的十进制调整指令
一般格式:DAA
功能:AL
调整后,得到的结果还是压缩型BCD码。
受影响标志位:AF
、CF
、PF
、SF
和ZF
(OF
无定义)
调整规则:
1)如果AL
的低四位大于9,或标志位AF=1
,那么,AL=AL+6
,并置AF=1
;
2)如果AL
的高四位大于9,或CF=1
,那么,AL=AL+60H
,并置CF=1
;
3)如果以上两点都不成立,则,清除标志位AF
和CF
。
- DAS(decimal adjust for subtraction)减法的十进制调整指令
一般格式:DAS
功能:AL调整后,得到的结果还是压缩型BCD码。
受影响标志位:AF
、CF
、PF
、SF
和ZF
(OF
无定义)
调整规则:
1)如果AL
的低四位大于9,或标志位AF=1
,那么,AL=AL-6
,并置AF=1
;
2)如果AL
的高四位大于9,或CF=1
,那么,AL=AL-60H
,并置CF=1
;
3)如果以上两点都不成立,则,清除标志位AF
和CF
。
- AAM(acsii adjust after multiplication)乘法的ASCII调整指令
一般格式:AAM
功能:该指令是用于调整寄存器AL
之值,该值是由两个单BCD码字节用无符号乘指令MUL
所得的积。
受影响标志位:PF
、SF
和ZF
(AF
、CF
和OF
等都是无定义)
调整规则:AH←AX div 10
(商),AL←AX mod 10
(余数)
例:
MOV AL, 9
MOV BL, 8
MUL BL ;AL=72D
AAM ;AH=7,AL=2
- AAD(ascii adjust for division)除法的ASCII调整指令
一般格式:AAD
功能:该指令是在作除法前用于调整寄存器AH
和AL
之值,它是把二个寄存器中单BCD码组成一个十进制数值,为下面的除法作准备的。
受影响标志位:PF
、SF
和ZF
(AF
、CF
和OF
等都是无定义)
调整规则:AL←AH*10+AL
,AH←0
例:除法前调整
MOV AX, 0502H
MOV AL,10D
AAD ;AH=0,AL=52D
DIV BL ;AH=2(余数),AL=5(商)
逻辑指令
逻辑运算指令
AND 逻辑与
OR 逻辑或
NOT 逻辑非
XOR 异或
TEST 测试
以上的这五条指令还是比较重要的,虽然说不是很难,在一些问题中还是要熟练掌握这些基本的指令,前四条我们基本已经知道概念了,但还是简单的回顾一下。
- AND(and)逻辑与
一般格式:AND DST, SRC
功能:将目的操作数和源操作数进行与运算,结果存入目的操作数中。可以屏蔽某些位,使某些位内容清0。
- OR(or)逻辑或
一般格式:OR DST, SRC
功能:将目的操作数和源操作数进行或运算,结果存入目的操作数中。可以置某些位为1。
- NOT(not)逻辑非
一般格式:NOT OPR
功能:将操作数进行逻辑非,将结果存入源操作数中。
- XOR(xor)异或
一般格式:XOR DST, SRC
功能:将目的操作数和源操作数进行异或运算,结果存入目的操作数中。可以使某些位变反;XOR
还可以判断两个操作数是否相等。
- TEST(test)测试
一般格式:TEST OPR1, OPR2
功能:将两个操作数进行与运算,但结果不进行保存,只根据其特征置条件码。可以测试某些位是否为0。
说明:
以上指令均对操作数按位进行二进制逻辑运算,其中NOT
指令不影响标志位;其它指令根据结果设置标志位PF
、SF
和ZF
,AF
无定义,CF
和OF
为0。通常在这些指令后使用条件转移指令来控制程序的执行顺序。
位测试指令
BT 位测试
BTS 位测试并置1
BTR 位测试并置0
BTC 位测试并变反
以上指令我们就不详细介绍了,学有余力的话再进一步去了解。
位扫描指令
BSF 正向位扫描
BSR 反向位扫描
同样,以上指令我们就不详细介绍了,学有余力的话再进一步去了解。
移位指令
SHL 逻辑左移
SAL 算术左移
SHR 逻辑右移
SAR 算术右移
- SHL(shift logical left)& SAL(shift arithmetic left)逻辑左移&算术左移
一般格式:SHL OPR, CNT
&SAL OPR, CNT
我们把这两个放在一起,是因为它们就是同一个指令,它们的作用是相同的。
他们的作用就是将目标操作数进行左移,在左移的同时在最右补0。就是这么简单。要注意的是,在所有的位移指令中,位移的次数大于1时,就需要把位移的次数放在CX
寄存器中,只有1能作为立即数出现在指令中,其余情况都是不允许的。
- SHR(shift logical right)逻辑右移
一般格式:SHR OPR, CNT
功能:将目标操作数进行逻辑右移,在右移的同时在最左边补0,也很简单。
- SAR(shift arithmetic right)算术右移
一般格式:SAR OPR, CNT
功能:将目标操作数进行算术右移,效果就是在右移的同时在最左补上原最高位,如目的操作数位0001 0110,则进行算术右移4位后为0000 0001;当目的操作数为1000 0010,则进行算术右移4位后,结果为1111 1000。就是将最左补上原来的最高位。
循环移位指令
ROL 循环左移
ROR 循环右移
RCL 带进位循环左移
RCR 带进位循环右移
- ROL(rotate left)循环左移
一般格式:ROL OPR, CNT
功能:将目的操作数进行循环左移,最高位移出到CF
,并同时移入最低位。
- ROR(rotate right)循环右移
一般格式:ROR OPR, CNT
功能:将目的操作数进行循环右移,最高位移出到CF
,并同时移入最高位。
- RCL(rotate left through carry)带进位循环左移
一般格式:RCL OPR, CNT
功能:将目的操作数进行带CF
循环左移,最高位移出到CF
,原CF
移入最低位。
- RCR(rotate right through carry)带进位循环右移
一般格式:RCR OPR, CNT
功能:将目的操作数进行带CF
循环右移,最低位移出到CF
,原CF
移入最高位。
以上这些指令对标志位的影响:若移位后符号位发生了变化,则OF=1
,否则OF=0
;若移位次数>1,则OF
无定义。CF
为最后移入位;不影响ZF
与SF
;AF
无定义。
串处理指令
MOVS ;串传送
CMPS ;串比较
SCAS ;串扫描
LODS ;从串取
STOS ;存入串
;下面三个为上面可用的前缀
REP ;重复
REPE ;相等/为零则重复
REPNE ;不相等/不为零则重复
所有串指令都可以处理字节或字。
- MOVS(move string)串传送
一般格式:
MOVS DST, SRC
MOVSB (字节)
MOVSW (字)
MOVSD (双字)
其中后三种格式明确的注明是传送字节、字或者双字。
MOVS执行的操作如下:
操作数类型 | 操作 |
---|---|
字节 | $ (Source-index)\pm1\to Source-index\\ (Destionation-index)\pm1\to Destionation-index $ |
字 | $ (Source-index)\pm2\to Source-index\\ (Destionation-index)\pm2\to Destionation-index $ |
在上述操作中,当方向标志位DF=0
时用+,DF=1
时用减。 Source-index
为源变址寄存器,当其地址长度为16的时候用SI
寄存器,Destionation-index
为目的变址寄存器,当其长度为16时用DI
寄存器。 MOVS
指令不影响标志位。
MOVS和REP联用
- 当
MOVS
与REP
联用时,源串必须在数据段中,目的串必须在附加段中,源串允许使用段跨越前缀来修改; - 为了建立方向标志,有两条指令要了解。
CLD:该指令使DF=0
,在执行串处理指令时可使地址自动增量
STD:该指令使DF=1
,在执行串处理指令时可使地址自动减量
下面为一个实例。数据段中有一个字符串,长度为17,要求将其传送到附加段中的一个缓冲区中。程序如下:
;********************************
datarea segment
mess1
datarea ends
;********************************
extra segment
mess2
extra ends
;********************************
code segment
.
.
.
lea si, mess1
lea di, mess2
mov cx, 17
CLD
REP MOVSB
code ends
- CMPS(compare string)串比较
一般格式:
CMPS DST, SRC
CMPSB (字节)
CMPSW (字)
功能如下:
操作数类型 | 操作 |
---|---|
字节 | $ (Source-index)\leftarrow (Source-index)\pm1\\ (Destionation-index)\leftarrow (Destionation-index)\pm1$ |
字 | $ (Source-index)\leftarrow (Source-index)\pm2\\ (Destionation-index)\leftarrow (Destionation-index)\pm2$ |
该指令把源地址寄存器指向的数据段中的一个字节、字或双字与目的变址寄存器所指向的附加段中的一个字节、字或者双字相减,但不保存结果,只根据结果置标志码,指令的其他特性和MOVS
的规定相同。
- SCAS(scan string)串扫描指令
一般格式:
SCAS DST
SCASB (字节)
SCASW (字)
功能如下:
操作数类型 | 操作 |
---|---|
字节 | $ (AL)-((Destionation-index)),(Destionation-index)\leftarrow (Destionation-index)\pm1 $ |
字 | $ (AL)-((Destionation-index)),(Destionation-index)\leftarrow (Destionation-index)\pm2 $ |
指令把AL
、AX
的内容与由目的变址寄存器指向的在附加段中的一个字符、字进行比较,并不保存结果,只根据结果设置条件码。指令的其他特性和MOVS
的规定相同。
- LODS(load string)从串取指令
一般格式:
LODS SRC
LODSB (字节)
LODSW (字)
功能如下:
操作数类型 | 操作 |
---|---|
字节 | $ (AL) \leftarrow ([DS:SI]),SI \leftarrow SI\pm1 $ |
字 | $ (AX) \leftarrow ([DS:SI]),SI \leftarrow SI\pm2 $ |
该指令把由源编制及存取从指向的数据段中某单元的内容送到AL
、AX
中,并根据方向标志和数据类型修改源变址寄存器的内容。
- STOS(store string)存入串指令
一般格式:
STOS DST
STOSB (字节)
STOSW (字)
功能如下:
操作数类型 | 操作 |
---|---|
字节 | $ [ES:DI] \leftarrow AL,DI \leftarrow DI\pm1 $ |
字 | $ [ES:DI] \leftarrow AX,DI \leftarrow DI\pm2 $ |
控制转移指令
无条件跳转指令
- JMP(jmp)跳转指令
条件转移指令
无符号数
- JZ(或JE)结果为0或相等转移
- JNZ(或JNE)结果不为0或不相等转移
- JS 结果为负则转移
- JNS 结果为正则转移
- JO 溢出则转移
- JNO 不溢出则转移
- JP 奇偶位为1则转移
- JNP 奇偶位为0则转移
- JB $<$则转移
- JNB $\geq$ 则转移
- JBE(或JNA)$\leq$ 则转移
- JA $>$ 则转移
- JCXZ
CX
寄存器的内容为0则转移
带符号数 - JL $<$ 则转移
- JNL $\geq$ 则转移
- JNG $\leq$ 则转移
- JG $>$ 则转移
循环指令
最常用的就是LOOP指令了,一般格式为:LOOP OPR
,CX
寄存器作为计数寄存器,没进行一次LOOP
指令,CX
就会减一,直到CX
减到0为止,LOOP
循环结束。
子程序
CALL 调用
RET 返回
中断
INT 中断
IRET 从中断返回(中断调用子程序特有)
处理器指令
CLC CF置0
STC CF置1
CLD DF置0
STD DF置1
CLI IF(中断标志)置1
STI IF置0
NOP 无操作指令
伪操作
段定义伪操作
表达式赋值伪操作
EQU&=
一般格式:Expression_name EQU Expression
它的作用就是给表达式赋予一个名字。
还有一个与EQU
相类似的伪操作=
也可以作为赋值伪操作使用。
注意:
我们来讨论一下EQU和=的异同点:
相同点:它们都是赋值伪操作,而且它们都不占据内存空间。
不同点:EQU
后面可以跟任何有效的操作数、任何可以求出常数值的表达式、任何有效的助记符,而且EQU
对于表达式名是不允许重复定义的。=
后面只能跟可以求出常数值的表达式,但=
可以重复定义。
本文地址:https://alphalrx.cn/index.php/archives/63/
版权说明:若无注明,本文皆为“LRX's Blog”原创,转载请保留文章出处。