#################所有汇编/DEBUG指令一览################# ##################################################### ##############第四章 8086调试、存储器、寄存器相关指令######## DOSBox设置盘并进入DEBUG操作: Z:\>mount d d:\DOSBOX\DOSBox_tool Z:\>d: D:\>DEBUG - (进入DEBUG) MS-DOS命令: cd\----------返回到根目录C>下 cd 目录名-------进入特定目录 cd..---------退回到上一级目录 d:----------进入到d盘 DEBUG下查看存储器情况: -d ds:0000 073F(数据段段地址):0000(偏移地址) (DEBUG的)存储器常用命令: 内存显示:D [地址] -D -------显示CS:IP(CS存放指令段地址,DS存放数据段地址,SS堆 栈段寄存器,ES附加段寄存器)开始的内存单元的内容。 -D 100------显示DS:0100H内容。只给出偏移量地址,则使用DS当前 值作为段地址。 -D DS:100-----显示DS:0100H内容。 -D 0100:2000----显示0100:2000H内容。 (每行16个字节单元) 内存修改命令E [地址](地址不可省略) 可以操作:(1)输入新值 (2)空格显示下一个单元的内容 (3)-显示上一个内容 (4)回车结束。 -E 100-----从DS:100处开始修改值(其他同D命令解释)。 -E SS:100----从SS:0100处修改。 -E 1202:0102----从1202H:0102H处修改。 00.表示内容不做修改。 __.__前面表示原值,后面表示修改值。 -E 地址数据表(以逗号或空格分开的若干十六进制字节或字符串) -E DS:100 'A' 1 '1'---将存储单元DS:0100H~DS:0102H的内容修改 成‘A’(ASCII码),1,‘1’(ASCII)。 内存复制命令M M 地址1 地址2 地址3---将地址1到地址2之间的数据复制到地址3, 其中地址2只能是偏移地址。 8086寄存器标志位的缩写形式 标志 OF DF IF SF ZF AF PF CF 1 OV DN EI NG ZR AC PE CY 0 NV UP DI PL NZ NA PO NC 8086三个控制标志:方向标志DF、中断允许标志IF、陷阱标志TF DEBUG下,TF标志位不显示。 寄存器命令R R显示所有寄存器内容和标志位状态。 R 寄存器名:显示、修改指定寄存器。先显示内容,在冒号后输入新 的值。 ###################################################### ###############第五章 指令的存储、寻址方式################## 汇编命令A:将用户输入的汇编语言汇编为机器码,相继的存储在从指 定区域开始的存储区中。格式:A [地址] -A-------从上一个A命令的最后一个单元开始;若为用过A命令,则缺 省为CS:IP。 -A 100------从CS:0100H开始汇编成机器代码。 -A CS:0220----从CS:0220H开始。 反汇编命令U:将二进制的机器指令变成助记符形式的汇编指令。 格式:U [地址](从指定指令地址开始反汇编32个字节) -U -----与-A类似进行反汇编 -U 100-----与上A类似,反汇编 -U CS:0220----从段地址:偏移地址开始反汇编 格式:U 地址范围 对指定范围的内容反汇编 -U 100 110-----将CS:0100H~CS:0110H的内容反汇编 -U CS:120 130----将CS:0120H~CS:0130H的内容反汇编 寻址方式 一.立即数寻址方式(操作数是8位(00H~0FFH)或 16位(0000H~0FFFFH)立即数) MOV AL,10----AL<---10H,源操作数是立即数寻址 二.寄存器寻址方式(操作数是寄存器的值,指令中是使用寄存器名, 包括8位通用寄存器(AH/AL/BH/BL/CH/CL/DH/DL)或16位 通用寄存器(AX/BX/CX/DX/SI/DI/BP/SP)和16位段寄存器 (CS/DS/ES/SS)。专用寄存器FLAGS和IP不可使用。CPU在 寄存器中得到操作数,不用访问存储器。) MOV AX,BX-----AX<----BX MOV DS,AX-----DS<----AX 三.存储器寻址方式(寻址主存中的操作数。此方式中,所用的寄存器 只能有基址寄存器BX或BP、变址寄存器SI或DI,不能用其他 任何寄存器) 1.直接寻址方式:指令中直接写出存储单元的变量名,或者地址。 操作数形式:[I8~I16] MOV AX,[2000]----[]里的数值作为EA,即AX<--DS:[2000H] EA=2000H MOV BX,X等价于MOV BX,[2000]----X:已定义好得字变量, 设X的偏移地址为2000H 2.段超越:当操作数在存储器中,系统根据隐含约定,自动将段寄存器 DS或SS的值作为段地址。当操作数不在隐含的段地址时,可以 使用隐含的段超越前缀代替其隐含约定。可以使用任意段寄存 器进行段超越,但只能在存储器操作之前。 段超越前缀形式: 段寄存器名: ;CS:,DS:,ES,SS (段超越属于直接寻址方式) 3.存储器间接寻址方式:先把存储单元的偏移地址事先存入某个寄存器,再通过这个 寄存器间接的找到这个存储单元。 操作数形式:[Reg],其中,Reg只能使用基址寄存器BX、BP或变址寄存 器SI、DI。 有效地址:EA=BX/BP/SI/DI。 默认的段地址在DS(若寄存器为BX、SI、DI)中或SS(若寄存器为BP) 中,但可以使用段超越前缀改变。 MOV AX,[SI]---------AX<--DS:[SI],EA=SI 4.寄存器相对寻址方式 操作数形式:[Reg+Disp]。其中,Reg只能使用基址寄存器BX、BP或变 址寄存器SI、DI,Disp是8位或16位偏移量。 有效地址:EA=BX/BP/SI/DI+Disp。 默认的段地址在DS(若寄存器为BX、SI、DI)中或SS(若寄存器为BP) 中,但可以使用段超越前缀改变。 MOV AX,[BX+2]---------AX<--DS:[BX+2],EA=BX+2 5.基址变址寻址方式 操作数形式:[Base+Index]。其中,Base只能是基址寄存器BX或BP, Index只能是变址寄存器SI或DI。 有效地址:EA=BX/BP+SI/DI。 默认的段地址在DS(若基址寄存器为BX)中或SS(若基址寄存器为BP) 中,但可以使用段超越前缀改变。 MOV AX,[BX+DI]--------AX<--DS:[BX+DI],EA=BX+DI 6.相对基址变址寻址方式 操作数形式:[Base+Index+Disp] 其中,Base只能是基址寄存器BX或BP,Index只能是变址寄存器SI或DI, Disp是8位或16位位移量。 有效地址EA=BX/BP+SI/DI+Disp。 默认的段地址在DS(若基址寄存器为BX)中或SS(若基址寄存器为BP) 中,但可以使用段超越前缀改变。 MOV AX,[BX+DI+2]------AX<--DS:[BX+DI+2],EA=BX+DI+2 三、寻址方式的多种表达方式 1.寄存器相对寻址或相对基址变址寻址方式中,位移量可用符号表示,符号地址在 汇编时,符号地址被转换为实际的偏移地址值。 MOV AX,[SI+Count]------Count是符号变量。 2.同一寻址方式可以写成不同形式。 MOV AX,[BX][SI]======MOV AX,[BX+SI] MOV AX,[BX+SI+Count]=== ==MOV AX,Count[BX][SI](Count[BX+SI]) 《汇编语言基础教程》为了描述方便,采用以下符号约定: Dest--------目的操作数 Src----------源操作数 Reg8--------任意一个8位通用寄存器AH/AL/BH/BL/CH/CL/DH/DL Reg16-------任意一个16位通过用寄存器AX/BX/CX/DX/SI/DI/BP/SP Reg----------Reg8/Reg16 Seg----------段寄存器CS/DS/ES/SS I8------------一个8位立即数 I16----------一个16位立即数 Imm--------I8/I16 Mem8------一个8位存储器操作数 Mem16-----一个16位存储器操作数 Mem-------Mem8/Mem16 四、寻址方式比较 立即数寻址方式一般用于对寄存器/存储单元赋值 寄存器寻址方式最简便、实用,执行速度快;缺点是寄存器数量少,不 能满足存储大量数据的要求。寄存器可以作为中间媒介重复使用。 存储器寻址方式解决了寄存器数量少的问题。缺点是执行时间长。但是 存储器寻址方式是一种重要的,必不可少的获取操作数的手段。 五、寻址方式的观察 1.跟踪命令T/P:从指令地址开始执行一条或多条指令 格式:T[=地址] 从指令地址开始执行一条指令,即单步调试。 T[=地址][N条] 从指令地址开始执行N条指令 T命令中若未指定地址,则从当前CS:IP开始执行。T命令执行的每条命 令后要显示所有寄存器和标志位的值及下一条指令。 T命令常结合A命令(汇编命令)使用。P命令的作用和格式与T命令相同, 当遇到中断指令和调用指令,应该使用P命令。因为T命令进入子程序可能无法返回; 而P命令则直接执行该指令,并将结果带回。遇到循环指令LOOP使用P命令,可以 使循环快速结束。P将CALL、INT或带有重复前缀(如REP)指令的执行当作一步, 不会,跟踪进入相应的过程或中断服务程序内部。 2.运行命令G:从指定地址开始执行命令,直到遇到断点或者程序结束返回操作系统 格式:G=[=地址][断点地址1][断点地址2]...[断点地址10] 其中,“=”后的地址指出的是程序执行的初始地址,如未指定,则缺省 为CS:IP。指定的断点最多为10个,也可以没有。 G指令从指令地址开始执行内存中的程序,直到程序结束或者遇到断点时 停止执行。若遇到断点,则显示所有寄存器和标志位的当前值以及要执行的下一条指 令。若程序正常结束,则显示"Program terminated normally"。 六、程序段的调试方法 DEBUG调试基础指令或程序段的基本步骤如下: (1)启动DEBUG.exe (2)利用汇编命令A,输入汇编语言指令序列。 (3)利用反汇编命令U,查看录入的指令序列是否正确。 (4)利用跟踪命令T,单步执行指令,观察每条指令执行情况,如结果、标志等。 (5)利用存储器查看指令D,查看存储单元内容。 (6)利用寄存器查看指令R,查看寄存器内容。 ########################################################## #####################第六章 指令系统#################### 一、通用数据传送指令:包括MOV和XCHG指令。实际传送类指令中除了标志寄存 器传送指令外,均不影响标志位。 1.传送指令:MOV 格式:MOV Dest,Src-------Dest<--Src 功能:将源操作数Src复制到目的操作数Dest,Src不变。 语法格式:MOV Reg/Mem/Seg,Reg/Mem/Seg/Imm (1)MOV指令可以实现立即数到寄存器/存储器/通用寄存器之间,寄存器和寄存 器间,通用寄存器和段寄存器之间,存储器和段寄存器之间的直接传送 Dest不能是CS。 注意:MOV主要任务满足大多数数据传送需求,对程序员限制多 (2)Dest与Src必须位数匹配。同时是字节或字。 ⅰ立即数没有明确的位数 ⅱ寄存器有明确的位数 ⅲ存储器操作的位数不确定,可以用byte ptr(字节)和word ptr(字)确定 ⅳ只要有一个操作数的位数确定即可 合法的MOV指令例: MOV AX,02------通寄<--立数,AX<--02H MOV BYTE PTR[2000],0-------存储<--立数,DS:[2000]<--0 MOV BX,AX------通寄<--通寄,BX<--AX MOV [1000],AX-------存储<--通寄,DS:[1000H]<--AX MOV DS,AX------段寄<--通寄,DS<--AX 非法的MOV指令例: MOV AX,BL----位数不匹配 MOV DS,1000----不允许立数直接到段寄 MOV [BX],[SI]----不允许存储间传送 MOV ES,CS----不允许段寄间传送 MOV CS,AX----CS不能做目的操作数 MOV [1000],02----位数不确定 2.交换XCHG 格式:XCHG Dest,Src----Dest<->Src 作用:源和目的操作数的内容互换 格式:XCHG Reg,Reg/Mem或XCHG Reg/Mem,Reg 说明:操作数的位数是字或字节 能在通寄间或通寄和存储间交换数据,不能在存储单元间交换。 源或目的操作数都不能是立即数 合法的XCHG指令(位置可以交换): XCHG AX,BX----AX<->BX XCHG AX,[BX+SI]----AX<->DS:[BX+SI] XCHG [2000],BX----DS:[2000H]<->BX 3.堆栈操作指令:PUSH进栈,POP出栈。 堆栈:SS记录堆栈段段地址,数据先进后出。 空栈时,栈顶栈底指向同一存储单元。 堆栈只有一个出口:栈顶。栈顶是地址较小的一端。由栈顶寄存器SP 指示。 堆栈操作只能以字为单位。 (1)进栈指令PUSH 格式:PUSH Src----SP(栈顶指针)<--SP-2 功能:16位操作数入栈 语法格式:PUSH Reg16/Mem16/Seg 入栈的16位操作数按“小段模式”存放。低字节存放在低地址,高字节高地址 例子:PUSH AX----将AX的值入栈 PUSH WORD PTR[2000]----将DS:[2000H]开始的第一个字入栈 (2)出栈指令:POP 格式:POP Dest----Dest<--SS:[SP],SP=SP+2 功能:16位操作数出栈 语法格式:POP Reg16/Mem16/Seg 说明:出栈16位操作数按“小端方式”取出。 操作数不能是CS 例子:POP AX----将栈顶的一个字弹出到AX POP WORD PTR[2000]----将栈顶的一个字弹出到DS:[2000H] 4.地址传送指令:LEA 格式:LEA Dest,Src----Dest<--Src的有效地址 功能:将存储器操作数的有效地址送至指定寄存器。 语法格式:LEA Reg16,Mem 说明:源操作数只能是存储器操作数;目的操作数只能是16位通用寄存器 LEA获取的是主存单元的有效地址,不是物理地址,也不是该单元的 内容。 LEA指令可以实现计算功能。 例子:MOV BX,0400----BX=0400H MOV SI,02----SI=02H LEA BX,[BX+SI]----BX=BX+SI=0400H+02H=0402H 第三条指令可以视为将BX和SI的内容相加,将结果送入到BX中。 I/O 8086用于寻址外设端口的地址线由16条,支持2^16=64k个8位端口。 I/O地址可以表示为:0000H~0FFFFH I/O直接寻址:由I/O指令直接提供8位I/O地址,最低寻址256个。(00H~0ffH) I/O间接寻址:用寄存器DX(16位寄存器)保存I/O地址。可寻址全部I/O 0~65535。端口号为0~255,端口号可以直接在指令中使用。否则, 由DX的值指定端口号。 5.输入/输出指令 (1)输入指令IN:将外设数据传送给CPU的AL/AX。 格式:IN AL/AX,Src----AX/AL<--Src指定的端口 功能:将Src指定端口的一个字节/字读入AL/AX 语法格式:IN AL/AX,I8/DX----I8为0~255的端口号 (2)输出指令OUT:将CPU的AL/AX数据传送给外设。 格式:OUT Dest,AL/AX----Dest指定的端口<--AL/AX 功能:将AL/AX的1个字/字节写到Dest指定的端口。 语法格式:OUT I8/DX,AL/AX----I8为0~255的端口号 传送字节数据用AL。 二、算术运算类指令 1.状态标志 (1)进位标志CF:若加法时结果最高位向前有进位或减法时最高位向前有 借位,则CF=1,否则CF=0. (2)溢出标志OF:十进制角度判断,若带符号数的运算结果超出了补码表 示的范围,则OF=1,否则OF=0.n位二进制带符号数的补码表示范围为-2^(n-1)~ 2^(n-1)-1。 从二进制角度判断,若两个数同号,而相加结果与之异号, 或者两个数已号,或者两个数异号,相减结果与被减数符号相反,则OF=1; 其他情况,OF=0. (3)清零标志ZF:运算结果为零,ZF=1,否则ZF=0. (4)符号标志SF:运算结果为负,则SF=1,否则SF=0.及SF取结果的最高位 (5)奇偶标志PF:当运算结果最低字节中“1”的个数为零或偶数时,PF=1 否则PF=0.PF标志仅反应最低8位中“1”的个数是奇是偶,即使是进行16位字操作 2.加法指令:包括ADD、ADC、INC,执行字和字节的加法运算。 (1)加法指令ADD: 格式:ADD Dest,Src----Dest<--Dest+Src 功能:源操作数Src和目的操作数Dest相加,结果送到Dest. 语法格式:ADD Reg/Mem,Reg/Mem/Imm 对标志位的影响:按状态标志的定义设置CF、OF、SF、ZF。 说明:两个操作数必须位数匹配,且不能同时是内存操作数。 MOV AL,FB----AL<--0FBH ADD AL,07----AL=FBH+07H=1111 1011B+0000 0111B=02H CF=1 运算251+7=258 1111 1011B 0000 0111B + ---------------- 10000 0010B (2)带进位加法指令ADC 格式:ADC Dest,Src----Dest<--Dest+Src+CF 功能:源操作数Src、目的操作数Dest以及CF相加 ,结果送到Dest。 语法格式:ADC Reg/Mem,Reg/Mem/Imm,同ADD指令 对标志位的影响:同ADD指令。 说明:(1)两个操作数必须是位数匹配,且不能同时是内存操作数。 (2)ADC指令常于ADD指令结合实现多精度相加。 MOV AX,4652----AX=4652H ADD AX,F0F0----AX=4652H+F0F0H=0100 0110 0101 0010B+1111 0000 1111 0000B=3742H,CF=1 运算18002+61680=79682 0100 0110 0101 0010B 1111 0000 1111 0000B + ------------------------ 1 0011 0111 0100 0010B 使用ADD没有进位使计算结果错误。 MOV DX,0234----DX=0234H ADC DX,F0F0----DX=0234H+F0F0H=0000 0010 0011 0100B+1111 0000 1111 0000B+CF=0F325H,CF=0 运算564+61680=62244 0000 0010 0011 0100B 1111 0000 1111 0000B + ------------------------ 1111 0011 0010 0100B (3)自增指令INC 格式:INC Dest----Dest<--Dest+1 功能:将目的操作数Dest加一,结果送到Dest. 语法格式:INC Reg/Mem 对标志位的影响:不影响CF,对其他状态位的影响同ADD指令。 3.减法指令:包括SUB、SBB、DEC、NEG、CMP指令,执行字或字节的减法运算 (1)减法指令SUB 格式:SUB Dest,Src----Dest<--Dest-Src 功能:目的操作数Dest减去源操作数Src,结果送到Dest. 语法格式:SUB Reg/Mem,Reg/Mem/Imm 对标志位的影响:按状态标志的定义设置CF、OF、SF、ZF。 说明:两个操作数必须是位数匹配,且不能同时是内存操作数。 MOV AL,FB----AL=0FBH SUB AL,7----AL=FBH-07H=0F4H,CF=0 MOV WORD PTR[200],4652----DS:[200H]=4652H MOV BX,1FE----BX=1FEH SUB AL,BL----AL=F4H-FEH=0F6H,CF=1 SUB WOED PTR[BX+2],F0F0----BX+2=1FEH+2==200H DS:[200H]=4652H-F0F0H=5562H,CF=1 (2)带错位减法指令SBB 格式:SBB Dest,Src----Dest<--Dest-Src-CF 功能:目的操作数Dest减去源操作数Src及CF,结果送到Dest. 语法格式:SBB Reg/Mem,Reg/Mem/Imm,同SUB指令。 对标志位的影响:同SUB指令 说明:(1)两个操作数必须是位数匹配,且不能同时是内存操作数。 (2)SBB指令常于SUB指令结合实现多精度相减。 例子:两个32位数0234 4652H和F0F0 F0F0相减,结果存放在DX.AX中 因为8086寄存器最多16位,32位数据相减要分成低16位和高16位, 低16位相减可能向高位借位,所以高16位应该把低16位的借位减掉,两者使用 的减法指令不同。 MOV AX,4652 SUB AX,F0F0----AX=AX-F0F0H=5562H,CF=1 MOV DX,234 SBB DX,F0F0----DX=1143H,CF=1 (3)自减指令DEC 格式:DEC Dest----Dest<--Dest-1 功能:Dest:目的操作数 语法格式:DEC Reg/Mem 对标志位的影响:不影响CF,其他同SUB指令。 例子:DEC CX----CX<--CX-1 (4)求补指令NEG 格式:NEG Dest----Dest<--0-Dest 功能:求补就是求相反数 语法格式:NEG Reg/Mem 对标志位的影响:以减法0-Dest的方式判断标志位的变化 MOV AX,FF64 NEG AL----AL=0-64H=9CH,OF=0,SF=1,ZF=0,PF=1,CF=1 (5)比较指令CMP 格式:CMP Dest,Src----Dest-Src 功能:将目操减源操,不将结果送到Dest。 语法格式:CMP Reg/Mem,Reg/Mem/Imm,同SUB。 对标志位影响:同SUB指令。 说明:(1)两个操作数必须是位数匹配,且不能同时是内存操作数。 (2)CMP与SUB的区别:CMP不将结果存入Dest。 (3)CMP用于比较两个数的大小,CMP指令后常跟转移指令,根据比较不同结果 ,产生不同的分支。 例子:比较AL是否大于64H CMP AL,64----AL-64H JB BELOW----AL<64H,转跳到BELOW执行 SUB AL,64----AL>=64H,AL<--AL-64H BELOW:... 注意:标号BELOW在DEBUG中是无法输入的,标号也就是符号地址,但是在输入 指令时,并不知道“BELOW”对应的地址是多少,因此要随便输入一个地址, 如:JB 0105;当输入到标号的真正位置时,可以看到标号位置应该为****。用A 命令修改JB 0105为正确位置,不必全部修改。 4.乘法指令:实现两个二进制操作数的乘法运算。包括无符号乘法指令MUL和带符 号乘法指令IMUL指令。 格式:MUL Src----无符号乘 IMUL Src----带符号乘 语法格式:MUL Reg8/Reg16/Mem8/Mem16----无符号字(8) 字节(16)乘,AX<--AL*Reg8/Mem8;DX.AX<--AX*Reg16/Mem16 IMUL Reg8/Reg16/Mem8/Mem16----带符号字(8) 字节(16)乘,AX<--AL*Reg8/Mem8;DX.AX<--AX*Reg16/Mem16 对标志位的影响:MUL:若积的高一半为0,则CF=OF=0,否则 CF=OF=1. IMUL:若乘机的高一半为低一半的符号扩展(全0或全1), 则CF=OF=0,否则CF=OF=1。对其他标志位无定义,即为任意。 例子:(1)无符号 MOV AL,B4 MOV BL,11 MUL BL----AX=AL*BL=180*17=3036=0BF4H,OF=CF=1,AX高8位不为零 (2)带符号 MOV AL,B4 MOV BL,11 IMUL BL----AX=AL*BL=-76*17=-1292=FAF4H,OF=CF=1,AX高8位含有有效 数字。 5.除法指令:实现两个二进制操作数的除法运算。包括无符号乘法指令DIV和带符 号乘法指令IDIV指令。 格式:DIV Src----无符号 IDIV Src----带符号 语法格式:DIV Reg8/Mem8-----无符号字节除 DIV Reg16/Mem16-----无符号字除 IDIV Reg8/Mem8-----带符号字节除 IDIV Reg16/Mem16-----带符号字除 功能:8位,AL<--AX÷Reg8/Mem8的商,AH<--AX÷Reg8/Mem8的 余数。 16位,AX<--DX.AX÷Reg16/Mem16的商,DX<--DX.AX÷Reg16/ Mem16的余数。 对标志位的影响:无定义 说明:(1)不能直接实现8位数除8位数或16位数除16位数。必须先把被除数零扩展 或符号扩展为16位或32位,然后用除法指令。 (2)对于DIV,余数的符号和被除数相同 (3)除数为0或商太大,可能出现溢出。 例子:(1)十六位除八位 0800H÷2=0400H----超出了8位表示范围,溢出。 (2)无符号除法 MOV AX,400 MOV BL,B4 DIV BL----商AL=1024/180=5=05H,余数AH=124=7CH (3)带符号除法 MOV AX,400 MOV BL,B4 IDIV BL----商AL=1024/(-76)=-13=F3H,余数AH=36=24H 6.符号扩展指令 对带符号数使用符号扩展,无符号数使用零扩展。 符号扩展:用操作数的符号位(即最高位)形成另一个操作数,所形成的这个操作 数全0或全1.符号扩展指令用来将字节转换为字,字转换为双字 零扩展:使高八位所形成的这个操作数全为零。 例子:8为带符号数1000 0001符号扩展为16为1111 1111 1000 0001 8位无符号数1000 0001零扩展为16位0000 0000 1000 0001 1.CBW指令:AL符号扩展为AX 功能:如果AL符号位为0,则AH=00H;为1,则AH=0FFH 对标志位无影响 例子:MOV AL,80----AL=80H=1000 0000H CBW----AX=1111 1111 1000 0000=0FF80H 2.CWD指令:AX符号扩展为DX 功能:如果AX符号位为0,则DX=0000H;为1,则DX=0FFFFH 对标志位无影响 例子:带符号数除法AX÷BX CWD IDIV BX 零扩展例子:进行无符号除法AX÷BX 分析:无符号除法用DIV,但是被除数的位数要为除数位数的两倍,要对AX零扩展 MOV DX,0====XOR DX,DX DIV BX 三、逻辑运算与位移类指令 1.逻辑运算指令:对字或字节按位进行逻辑运算,包括AND(与)、OR(或)、 NOT(非)、XOR(异或)和TEST(测试)。 双操作数的逻辑运算指令的相同点: 对操作数的要求和格式都相同; 两个操作数必须都转换成二进制数运算; 两个操作数必须位数匹配,不能同时是存储器操作数; 对于标志位,都是CF=OF=0,根据结果设置SF、ZF和PF,对AF无定义 (1)逻辑与指令AND 格式:AND Dest,Src----Dest<--Dest AND Src 功能:源操Src和目操Dest按位与,结果送到Dest. 语法格式:AND Reg/Mem,Reg/Mem/Imm 对标位影响:CF=OF=0,根据结果设置SF、ZF、PF,对AF位定义 AND指令的应用:对指定位清零,但不影响其他位。将清零位与0,不变位与1 例子:将BL中D0和D3清零,其他不变。 AND BL,F6----F6H=1111 0110 **** **** AND 1111 0110 ------------ **** 0**0 对BL所有位清零:AND BL,0 或MOV BL,0 或XOR BL,BL (2)逻辑或指令OR 格式:OR Dest,Src----Dest<--Dest OR Src 功能:按位执行或,结果送到Dest. 语法格式:OR Reg/Mem,Reg/Mem/Imm 对标为影响:CF=OF=0,根据结果设置SF、ZF、PF,对AF位无定义 OR指令应用:对指定为置1,不影响其他位。想要置1的位或1,保持不变位或0. 例子:OR BL,9----0000 1001B=9 对BL所有位置1:OR BL,FF 或MOV BL,FF (3)逻辑非指令NOT 格式:NOT Dest----Dest<--NOT Dest 功能:目操按位执行非操作,结果送到Dest 语法格式:NOT Reg/Mem 对标为影响:无 说明:NOT时逻辑指令,NEG是求补指令 例子:对BL所有位求反:NOT BL (4)逻辑异或指令XOR 格式:XOR Dest,Src----Dest<--Dest XOR Src 功能:按位执行异或,结果给Dest. 语法格式:XOR Reg/Mem,Reg/Mem/Imm 对标志位的影响:CF=OF=0,根据结果设置SF、ZF、PF,对AF位无定义 XOR应用:对指定位求反,不影响其他位。要求反的位异或1,保持不变的异或0. 例子:对BL的D0和D3求反:XOR BL,9----0000 1001B=9 (5)测试指令TEST 格式:TEST Dest,Src----Dest AND Src 功能:源操和目操按位执行与,Src和Dest都不变,影响标志位。 语法格式:TEST Reg/Mem,Reg/Mem/Imm 对标为影响:和AND指令一样 说明:(1)TEST不影响目的操作数,其与AND的关系类似CMP和SUB (2)TEST指令常用来检测一些条件是否满足,但不改变原操作数的情况。这条指令 后面一般是条件转移指令,以利用不同的条件转向不同的程序段。 例子:检测BL中D0和D3是否为零 TEST BL,9----0000 1001B=9,若BL中检测位至少有一位为0,则ZF=0;否则ZF=1 JNZ THERE----标志ZF=0,即D0或D3等于1,则程序转移到THERE ...----否则ZF=1,即D0和D3=0,顺序执行 THERE:... 1111 0111 TEST 0000 1001 ------=--=-- 0000 0001 TEST指令常用于检测一些条件是否满足,但又不希望改变原操作数的情况 2.位移指令:分为逻辑位移和算数位移,分别具有向左或向右的操作。MSB表示二 进制数最高位;LSB表示二进制数最低位。 (1)一般格式: SHL Dest,Src----Dest逻辑左移 SHR Dest,Src----Dest逻辑右移 SAL Dest,Src----Dest算术左移,同SHL SAR Dest,Src----Dest算数右移 算术右移(SAR)是将各位依次右移指定位数,然后在左侧用原符号位补齐。 (2)语法格式 SHL Reg/Mem,1/CL 功能:Dest左移1/CL位,最低为补0,最高位进入CF SHR Reg/Mem,1/CL 功能:Dest右移1/CL位,最低为补0,最高位进入CF SAL Reg/Mem,1/CL 功能,同SHL SAL Reg/Mem,1/CL 功能:Dest右移1/CL位,最高位不变,最低为进入CF 说明:(a)源操作数表示位移位数,该操作数为1,表示移动一位;当位移位数大 于一时,则用CL寄存器值表示,该操作数表达为CL; (b)DEBUG调试时,SAL指令不能被识别,用SHL指令代替 (3)对标志位的影响 按移入的位设置CF,根据位移后的结果影响SF、ZF、PF,对AF没有定义。 若位移后符号位发生了变化,则OF=1,否则OF=0;若位移的次数大于1,则OF无 定义 逻辑左移指令SHL执行一次位移,相当于无符号数乘以2. 逻辑右移指令SHR执行一次位移,相当于无符号数除以2. 算数右移指令SAR执行一次位移,相当于无符号数除以2.SAR指令产生的 结果与等效的IDIV指令的结果可能不同。 例子:SI<--4*AX+AX MOV SI,AX MOV CL,2 SHL SI,CL----SI<--4*AX ADD SI,AX----SI<--4*AX+AX 3.循环位移指令 循环位移指令分成带进位和不带进位,分别由左移和右移。 (1)一般格式 ROL Dest,Src----Dest不带进位循环左移 ROR Dest,Src----Dest不带进位循环右移 RCL Dest,Src----Dest带进位循环左移 RCR Dest,Src----Dest带进位循环右移 (2)语法格式 ROL Reg/Mem,1/CL 功能:Dest左移1/CL位,最高位进入CF和最低位。 ROR Reg/Mem,1/CL 功能:Dest右移1/CL位,最高位进入CF和最低位。 RCL Reg/Mem,1/CL 功能:Dest左移1/CL位,最高位进入CF,原CF进入最低位 RCR Reg/Mem,1/CL 功能:Dest右移1/CL位,最低位进入CF,原CF进入最高位 说明:源操作数表示位移位数,该操作数为1,表示移动一位;当位移位数大 于一时,则用CL寄存器值表示,该操作数表达为CL; (3)对标志位的影响 按移入的位设置CF,不影响SF、ZF、PF、AF。若位移后符号位 发生了变化,则OF=1,否则OF=0;若位移的次数大于1,则OF无定义。 例子:将DX:AX(意义:用两个寄存器表示32位数)中的32位数左移一位 SHL AX,1 RCL DX,1 分析:AX:DX左移一位后,AX的最高位成为DX的最低为,而AX的最高位无法直接 移入DX的最低位。因此,需要借助一个中转CF。AX左移后,AX的最高位进入CF, DX再通过带进位的循环左移,使CF成了DX的最低位。 四、控制转移类指令 8086CPU以CS:IP指向下一条要执行的指令。控制转移类指令通过修改CS:IP的值 可以改变程序的顺序流程,从而实现分支与循环等控制结构。 1.无条件转移指令JMP 格式:JMP Dest----转移到Dest指定的目标地址处 常用JMP语法格式:JMP Lable----Lable与该指令位于同一代码段, IP=Lable的偏移地址 Lable与该指令不位于同一代码段,CS:IP=Lable的分段地址 JMP Reg16/Mem16----IP=Reg16/Mem16 对标志位影响:无 其中Lable为标号。对于程序员,通常用标号指出目标地址。 例子:设GO为同一代码段的标号,实现转移到GO (1)JMP GO ... GO: (2)LEA BX,[1000]----地址传送指令。设GO的偏移地址为1000H JMP BX (3)JMP WORD PTR[BX] 2.条件转移指令 条件转移指令是根据上一条指令影响或设置的标志位或CF的值作为判断条件,若 满足条件则转移到指令所指的地址处执行,若不满足则顺序执行下一条指令。 (1)条件转移指令Jcc 格式:Jcc Lable----条件满足,转移到Lable;否则,顺序执行。 对标志位的影响:无 Jcc指令包括下列3类 (a)测试单个标志位的Jcc指令 Jcc | 描述 JC,JB,JNAE |有进位时转移(CF=1) JNC,JNB,JAE |无进位时转移(CF=0) JZ,JE |为零(相等)时转移(ZF=1) JNZ,JNE |非零(不等)时转移(ZF=0) JS |为负时转移(SF=1) JNS |为正时转移(SF=0) JO |溢出时转移(OF=1) JNO |不溢出时转移(OF=0) JP,JPE |1的个数为偶数时转移(PF=1) JNP,JPO |1的个数为奇数时转移(PF=0) 例子:计算DX<--|AX-BX|(绝对值) SUB AX,BX----AX<--AX-BX JNS NONEG----为正是转到NONEG NEG AX----NEG是求补指令 NONEG: MOV DX,AX 同样,转移到的地址一开始不知道,等到出现后再用A指令修改 (b)用于无符号数比较的Jcc指令 Jcc | 描述 JA,JNBE |高于(不低于等于)时转移(CF=0且ZF=0) JAE,JNB,JNC |高于等于(不低于)时转移(CF=0) JB,JNAE,JC |低于(不高于等于)时转移(CF=1) JBE,JNA |低于等于(不高于)时转移(CF=1或ZF=1) 说明:A即Above,B即Below,E即Equal,N即Not 例子:比较AX=5H,BX=0FFFFH的大小,较大的数存入AX中。AX与BX均为无符号 数。 CMP AX,BX----比较AX和BX JNB NEXT----若AX>=BX转移 XCHG AX,BX----若AXOF) JLE,JNG |小于等于(不大于)时转移(SF<>OF或ZF=1) 说明:G即Greater,L即Less,E即Equal,N即Not 例子:仿照上一例题 (2)循环指令 循环流程的条件一般是循环计数,用循环计数来控制循环次数。循环流程也可以用 前面的条件转移类指令来实现。循环次数确定,用循环指令;不确定,用条件转移 指令。 (a)循环指令JCXZ 格式:JCXZ Lable----若CX=0,则转移到Lable 对标志位无影响 (b)循环指令LOOP 格式LOOP Lable----CX=CX-1,若CX<>0,则转移到Lable。 对标志位无影响 说明:(a.)JCXZ直接判断CX的值是否为0 (b.)LOOP时CX先减一,后判断。若CX的初值等于0,则LOOP指令的循环将执行 到65536次。 例子: MOV CX,5 JCXZ OK----如果CX为0,就跳过循环 NEXT:... LOOP NEXT OK:... (3)串操作类指令 以字节或字节为单位的多个数据存放在连续的主存储区域中形成数据串,即数组 处理器控制类指令用来控制各种CPU的操作,如空操作、暂停等。 例子:Db 1 2 3 4 5----数组,DB为变量定义伪指令 Db ‘ABCDE’----字符串 (a)串操作类指令的特点 内存可以和寄存器交换数据,也可以被赋予立即数。串操作就是CPU去完 成某一数量的、重复的内存操作。 串操作指令的操作对象是以字(W)为单位的字串,或是以字节(B)为 单位的字节串。 (a.)串寻址方式 (b.) 源操作数用寄存器SI寻址,默认在数据段DS中,但允许段超越:DS:[SI]; 目的操作数用寄存器DI寻址,默认在附加字段ES中,不允许段超越:ES:[DI] 每执行一次串操作指令,SI和DI将自动修改:+-1(对于字节串)或+-2 (对于字串)。 (c.)方向标志DF DF在串操作指令中控制地址的变化方向。DF=0,地址指针增1或2; DF=1,地址指针减1或2. (d.)DF指令处理标志 方向标志DF用指令CLD清零或STD置1. DF标志处理指令语法格式: CLD----DF=0 STD----DF=1 对标志位影响:只影响DF (b)串操作指令 指令包括MOVS、LODS、STOS、SCAS或CMPS。为了指出操作对象的 长度,在助记符后加上B或W,分别表示操作类型为字或字节。 (a.)串传送指令MOVS 格式:MOVSB MOVSW 功能:把字节或字操作数从主存的源地址传送至目的地址 ES:[DI]<--DS:[SI]; IF(DF=0) THEN SI=SI+size; DI=DI+size; ELSE SI=SI-size; DI=DI-size; 对标志位影响:无 说明:(1)源和目的操作数都是内存操作数,可实现内存单元内直接传送数据 (2)size=1(MOVSB)或2(MOVSW) 例子:将数据段1000H处开始的5个字节传送到附加段2000H开始的存储区 MOV SI,1000 MOV DI,2000 MOV CX,5----CX<--传送次数 CLD----DF=0,地址增加 AGAIN:MOVSB----传送一个字节 DEC CX----传送次数减一 JNZ AGAIN----判断传送次数CX是否为0.不为0,则到AGAIN位置执行 指令 (b.)串存储STOS 语法格式:STOSB STOSW 功能:把AL或AX数据传送至目的地址。 ES:[DI]<--AL/AX; IF(DF=0) THEN DI=DI+size; ELSE DI=DI-size; 说明 :size=1(MOVSB)或2(MOVSW) 对标志位无影响 例子:将附加段1000H开始的5个字设置为0 MOV AX,0 MOV DI,1000 MOV CX,5 CLD----DF=0,地址增加 AGAIN:STOWS----传送一个字 DEC CX---传送次数减一 JNZ AGAIN----判断传送次数CX是否为0. (c.)串读取指令LODS 格式:LODSB LODSW 功能:把指定主存单元的数据传送给AL或AX AL/AX<--DS:[SI] IF(DF=0) THEN SI=SI+size; ELSE SI=SI-size; 说明 :size=1(MOVSB)或2(MOVSW) 对标志位无影响 (d.)串比较指令CMPS 格式:CMPSB CMPSW 功能:将主存中的源操作数减去至目的操作数,以便设置标志,进而比较 两操作数的关系。 DS:[SI]-ES:[DI] IF(DF=0) THEN SI=SI+size; DI=DI+size; ELSE SI=SI-size; DI=DI-size; 对标志位影响:无 说明 :size=1(MOVSB)或2(MOVSW) (e.)串扫描指令SCAS 格式:SCASB SCASW 功能:将AL/AX减去至目的操作数,以便设置标志,进而比较AL/AX与 操作数的关系。 AL/AX<--ES:[DI] IF(DF=0) THEN DI=DI+size; ELSE DI=DI-size; 对标志位影响:无 说明 :size=1(MOVSB)或2(MOVSW) 例子:附加段1000H处存放一长度为5的字符串,查找是否有空格字符。 MOV DI,1000 MOV AL,20----20H为空格的ASCII码 MOV CX,5 CLD AGAIN:SCASB----搜索 JZ FOUND----为0(ZF=1),发现空格 DEC CX----不是空格 JNZ AGAIN----搜索下一个字符 ... FOUND:... #################################################### ###############第七章 中断和DOS系统功能调用############## 一、 汇编程序通常并不给程序员提供任何函数或程序库,所以必须利用操作系统的编程 资源。DOS提供给程序员的编程资源是以中断调用的方法使用的子程序。 中断源-->硬中断(外部中断)-->不可屏蔽中断(不受CPU IF位控制) | | v v 软中断(内中断) 可屏蔽中断(受CPU IF位控制) (不受CPU IF位控制) 软中断是由CPU内部的某个事件引起的,主要由3个情况引起(1)中断指 令;(2)CPU的某些错误;(3)DEBUG的设置 汇编语言中,主要使用的是软中断。中断是实现CPU大多数功能调用的主 要方式。 80X86系统允许256种中断,每种中断对应0~255唯一编号,称为中断号 1、中断向量与中断向量表 每种中断都有对应的中断服务程序。实模式下,中断服务程序的入口地址 称作中断向量,存放256个中断向量的内存区域为中断向量表。 每个中断向量占4个字节,用32位分段地址描述。中断向量表位于内存地 址00000H~003FFH,共1KB(256*4B)。对于中断号n,中断向量所在地址4n~ 4n+3。中断向量表在系统复位时初始化。 例子:0号中断的中断向量地址00000H,1号中断的中断向量地址00004H 2、控制标志IF和TF (1)中断允许标志IF 用于控制CPU是否响应外部可屏蔽中断请求。若IF=1,则允许中断; IF=0,禁止中断。 格式:CLI----IF=0 STI----IF=1 对标志位只影响IF 注意:在系统中应慎重使用CLI指令,错误的使用将导致系统无法正常工作。 (2)单步标志TF 用于控制CPU是否进入单步调试模式方式。TF=1,CPU执行单步。 3、中断响应过程 当中断发生时,由硬件自动完成下列操作 (1)标志寄存器FLAGS进栈 (2)置IF=0,TF=0 (3)返回地址(CS:IP)进栈 (4)根据中断号n,从地址0:n*4取出4字节的中断向量,低字节送IP,高字节送CS (5)转去执行中断向量指向的中断服务程序。 二、常用中断指令 1.中断调用指令INT 格式:INT n----调用中断号为n(0~255)的中断服务程序 功能:(1)标志寄存器FLAGS进栈 (2)置IF=0,TF=0 (3)返回地址(CS:IP)进栈 (4)根据中断号n,从地址0:n*4取出4字节的中断向量,将改字送 CS:IP 对标志位的影响:IF=TF=0,不影响其他标志。 2.中断返回指令IRET 格式:IRET----从终端服务程序返回 功能:从栈里弹出一个双字到CS:IP,再弹出一个字到FLAGS 三、DOS系统功能调用 功能调用以中断服务程序的形式存在,每类服务对应一个中断号。通常 INT指令调用DOS提供的服务实现I/O操作,以减少对硬件环境的依赖。DOS系统 中,主要分配21H号中断用于程序员调用DOS操作系统功能。DOS功能调用的子程序 已按顺序编号,称为功能号。 1.调用的一般方法 (1)在寄存器AH中设置系统功能调用号,说明选择的功能 (2)在指定寄存器中设置入口参数 (3)用中断调用指令INT 21H执行功能调用 (4)根据出口参数分析功能调用执行情况 2.输入/输出类功能调用 《汇编语言基础教程》中要求的基本DOS功能调用 功能号 功能 入口参数 出口参数 AH=01H 输入一个字符 AL=输入字符的 AH=02H 输出一个字符 DL=字符的ASCII AH=09H 输出一个字符串 DS:DX=字符串地址(首地址) AH=0AH 输入一个字符串 DS:DX=缓冲区地址 AH=4CH 程序终止结束 AL=返回代码ASCII (1)字符输入 功能:获得按键的ASCII码值。调用此功能时,若无按键按下,则会一直 等待,直到按键后才读取该键值。 例子:从键盘输入一个字符。 MOV AH,01----功能号AH=01H INT 21----调用功能 遇到指令INT n,要把INT n当作整体运行,否则会进入到中断程序中。 (2)字符输出 功能:在显示器当前光标位置显示给定的字符,光标右移一个字符位置。 如按Ctrl+Break或Ctrl+C则推出 例子:在显示器前显示一个问号 MOV AH,02----功能号AH=02H MOV DL,3F----'?'ASCII码为3FH。提供入口参数:DL<--'?' INT 21----DOS功能调用:显示 NOP----空操作指令,占用一个机器周期 (3)字符串输入 功能:从键盘上输入字符串 说明:(1)用户按键,最后用回车确认 (2)0AH号DOS功能要设置保存输入字符串的缓冲区,其缓冲区的格式如下 第一字节最多接受的字符个数(包括回车字符,可以是1~255) 第二字节存放实际输入的字符个数(不包括回车符) 第三字节开始将存放输入的字符串。实际输入的字符数多于定义数时,多余的字符 丢掉,并响铃。 例子:用0AH号DOS系统功能调用从键盘输入一个字符串。 BUFFER DB 5----定义缓冲,第1个字节是可能输入的最大字符数,DB见后文 DB 0----存放实际输入的字符串,DEBUG能识别DB DB 5 DUP(0)----存放输入的字符串 ... MOV DX,SEG BUFFER----伪指令Seg取得buffer的段地址,Seg见后文 MOV DS,DX----设置数据段DS MOV DX,OFFSET BUFFER----伪指令Offset取得buffer的偏移地址,Offset见后文 MOV AH,0A INT 21 注意:SEG、OFFSET用实际值替换 存储单元从Buffer开始地址递增 (4)字符串输出 功能:在显示器输出指定的字符串 说明:(1)字符串应以$(24H)结束 (2)可以输出回车(0DH)和换行(0AH)字符产生回车和换行作用 例子:用09H号DOS系统功能调用在显示器上输出一个字符串。 STRING DB 'ABC','$'----在数据段定义要显示的字符串 ... MOV AN,09----功能号AH=09H MOV DX,SEG STRING----提供入口参数:DS<--字符串的段地址 MOV DS,DX MOV DX,OFFSET STRING----提供入口参数:DX<--字符串的偏移地址 INT 21----DOS系统调用:显示 NOP #################################################### ############第八章、汇编语言程序格式##################### 完整的汇编语言程序需要指令外,还需要伪指令。 高级语言程序员编程时,用户无需考虑存储空间的分配,操作系统和编译 软件解决了这个问题;对于低级语言程序员,存储空间不再透明。指令是无法实现对 存储空间的分配,这个指令由伪指令完成。 汇编语言开发是先利用某种编译器编写汇编语言原程序(*.ASM),然后 经过汇编得到目标模块文件(*.OBJ),连接后形成可执行文件(*.EXE)。本书 采用MASM6.X为蓝本,借助它来理解汇编语言和机器结构。 一、汇编语言语句格式 构成汇编语言源程序的语句主要包括两类:指令和伪指令。指令即硬指令 在程序运行期间由CPU执行,汇编后由对应机器码取代。汇编语言对大小写不敏感。 伪指令是不可执行的,它只在源程序汇编期间由汇编程序处理的命令, 用于告诉汇编程序如何进行汇编的指令,它既不控制机器的操作,也不被编译成机器 码。只能为汇编程序所识别并指导汇编如何进行,相对于程序或寄存器的地址载入。 1.汇编语言源程序由语句序列构成,其语句由两种格式 (1)说明性语句 由伪指令构成,通常指示汇编程序如何汇编源程序,即: 名字 伪指令助记符 参数,参数... ... ;注释 其中名字可以是变量名、子程序名等,既反映逻辑地址,又具有自身的各种属性 (2)执行性语句 由硬指令构成的语句,通常对应一条机器指令,出现在程序的代码段中。 即:标号:硬指令助记符 操作数,操作数... ...;注释 其中,标号是逻辑地址,为控制转移类指令提供转移的目的地址。 标号和名字是符合汇编语法的用户自定义的标识符,每个标识符的定义 是唯一的。标识符一般最多由31个字母、数字及规定的特殊符号($,?等)组成, 不能以数字开头。标识符不能是汇编语言的保留字。汇编语言的保留字主要有硬指令 或伪指令助记符、运算符、寄存器名等。 例子:MOV AX,0----执行性语句 BUFFER DB 1,2,3,4----数据定义伪指令 2.DEBUG和MASM环境对指令的不同处理。 (1)DEBUG把键入的数字看作16进制数,键入16进制数不能加H。其他要加后缀 说明 MASM默认输入为10进制数,其他要加后缀说明。 (2)字符与字符串 字符与字符串必须用单引号或双引号括起来。例子:'a','Hello','World' 单个字符相当于整数,值为ASCII码;字符串一般位于BD指令后。 说明:(a)DEBUG不识别单引号,所以DEBUG里输入字符,只能输入字符的ASCII (b)MASM里输入字符,单引号引起的字符和ASCII等效。 (3)数值表达式 汇编语言在汇编过程中计算表达式,最终得到一个表达式。 MASM 6.X支持多种运算符 算术运算符 +,-,*,/,MOD(取余) 逻辑运算符 AND,OR,XOR,NOT 位移运算符 SHL,SHR 关系运算符 EQ(相等),NE(不相等),GT(大于),LT(小于), GE(大于等于),LE(小于等于) 高低分离符 HIGH(高字节),LOW(低字节) 3.变量和标号 (1)变量定义伪指令 变量定义伪指令为变量分配存储空间,并设置相应存储单元的初始值。 格式:[变量名] 变量定义符 操作数 [, ...,操作数] 变量名为用户自定义符,表示其后操作数的首地址,用这个符号表示地址 常称为符号地址;变量名可以没有,汇编程序将直接为初值表分配空间,无符号地址 给出变量名为了方便存取所指使的存储单元。多个操作数组成一个数组。 变量定义符常用的主要有以下几种: DB:定义字节,每个操作数站一个字节; DW:定义子,每个操数占一个字; 在调试器DEBUG下,A命令提供能够使用的伪指令仅有DB和DW两个。 操作数可以是常数、表达式、?、DUP等。?表示未赋初值,只保留内存空间。重复 初值可以用DUP定义。DUP格式如下:重复次数 DUP (操作数,...,操作数) 说明:(a)定义一个ASCII字符或字符串一般使用DB伪指令,对存储单元的分配有特殊要 求时,也可以用DW伪指令。 (b)带符号数以补码形式存放 (c)DEBUG里不使用变量,MASM才使用变量。 例子:.data----定义数据段 X DB 'a',-5----‘a’-->61H,-5-->0FBH(-5的补码) DB 2 DUP(100)----100-->64H Y DB 'abc'----<-->Y DB 'a','b','c'<-->Y DB 61H,62H,63H (2)变量和标号的属性 汇编语言四个组成部分: 标号 表示其所指存储单元的逻辑地址,指示硬指令的地址 变量名 指示所定义变量的开始地址 段名 指示相应段的起始地址 子程序名 指示相应子程序的起始地址 标号和名字具有两类属性 地址属性:对应存储单元的逻辑地址,包括段地址和偏移地址 类型属性:类型可以是NEAR和FAR,分别表示段内和段间;变量名的类型 可以是BYTE和WORD等。 说明:(a)DEBUG里使用变量或标号的地址 (b)MASM里直接使用变量名或标号 例子:比较无符号数大小。较大的数存入AX。设AX=5,BX=0ffffh DEBUG CMP AX,bx JNB 0106(这里是地址) JNB 0102(这里指JNB 0106行) XCHG AX,BX MASM CMP AX,BX JNB NEXT XCHG AX,BX NEXT:... (a)地址操作符 地址操作符取得名字或标号的段地址和偏移地址,汇编时用MASM自动计算。常用的 地址操作符如下: OFFSET 变量名字/标号----返回名字或标号的偏移地址 SEG 变量名字/标号----返回段地址 LEA指令和OFFSET伪指令的比较:(a.)LEA各种寻址方式,OFFSET只能 用于变量和标号 (b.)对简单变量,OFFSET比LEA执行速度快。因为MOV BX,OFFSET TABLE指令 在汇编时,由汇编程序计算TABLE的偏移地址,并被汇编车成立即数传送指令。因此 效率高。LEA在执行时才计算地址,再送到指定寄存器中。 (c.)OFFSET在DOS的输入/输出类功能调用里经常用到。 (b)类型操作符 对名字和符号的类型进行有关设置。常用类型运算符如下: 类型名 PTR 内存操作数/标号 名字和标号有指定的类型,而地址不变。类型名为:BYTE、WORD等, 或者是NEAR、FAR。 (c)其他操作符 TYPE 名字/标号----返回一个常数,表示名字/变量的类型。对于BYTE和 WORD类型,分别返回1和2。 LENGTHOF 名字/标号----返回直接分配给指定变量的元素个数 SIZEOF 名字/标号----返回直接分配给指定变量的字节数,即: SIZEOF 名字/标号=TYPE 名字/标号*LENGTHOF 名字/标号 例子:DB ?,‘abcd’----TYPE=1,LENGTHOF=5,SIZEOF=5 二、符号定义伪指令 在程序设计中,可能会多次用同一个表达式,为减少重复书写的麻烦。 汇编语言提供了“EQU”和“=”伪指令。 1.伪指令EQU 格式:符号名 EQU 表达式 功能:用符号名代表表达式或表达式的值 说明:表达式可以是任何有效的形式,如常数、数值表达式等,甚至是 伪指令定义的另一个名称。但EQU定义的符号名在在同一个程序中只能定义一次 2.伪指令= 格式:符号名 = 表达式 功能:用符号名代表表达式或表达式的值 说明:功能与EQU类似,区别是=定义的符号名在同一个程序中可以重新 定义。 例子:EQU和=示例 NUM EQU 2*3----NUM代表表达式的值 ERR EQU 'ERROR'----ERR代表字符串 MOVE EQU MOV----指令MOV定义为MOVE VALUE=0 VALUE=2*3----=定义的符号名重新定义 三、过程 定义:当一段程序需要在一个或多个程序的多处被使用时,为简化设计,通常 将这段程序抽取出来,定义为过程。过程是功能相对独立的一段程序,有叫子程序。 1.过程定义:由伪指令PROC与ENDP实现 格式:过程名 PROC [NEAR/FAR] 过程体 过程名 ENDP 注意:过程名在整个程序中必须是唯一的。过程名本质和标号一样,其属性为NEAR或 FAR,缺省为NEAR。NEAR属性的过程只能被相同代码段的其他程序调用, 为段内近调用;FAR可以被相同或不同代码段的程序调用,为段间远调用。 一般情况下,[NEAR/FAR]被省略,根据过程定义伪指令,汇编程序自动 确定段内还是段间。 例子:实现回车、换行功能的子程序,定义过程如下: PROC1 PROC----过程属性默认为NEAR PUSH AX----保护AX、DX PUSH DX MOV DL,0DH----回车的ASCII为0DH MOV AH,2 INT 21H MOV DL,0AH----换行的ASCII为0AH MOV AH,2 INT 21H POP DX----恢复AX、DX POP AX RET----子程序返回 PROC1 ENDP----子程序结束 2.过程调用和返回 过程调用和返回由CALL和RET。 过程调用时CALL指令:将其下一条指令(返回地址)进栈,然后将控制转移到过程, 从过程的第一条执行 执行到RET指令:弹出栈顶内容作为返回地址,使指令转移到CALL指令的下一条指令, 继续执行。 (1)过程调用指令CALL 常用CALL指令语法格式: CALL LABEL----段内调用,SP<--SP-2,SS:[SP]<--IP,IP=LABEL 功能: 返回地址(IP:下一条指令的偏移地址)进栈,偏移到过程的第一条指令。 CALL和JMP指令的区别:返回地址压入堆栈。CALL是调用跳转,在执行到RET指令后 会返回到CALL后继续执行;JMP是无条件跳转,不会跳回。 (2)过程返回指令RET 常用RET指令语法格式: RET----段内返回,IP<--SS:[SP],SP<--SP+2 功能: 返回地址出栈,POP一个字到IP 例子:在主程序中调用PROC1 主程序 . . . CALL PROC1 . . . 子程序 3.汇编语言源程序结构 8086按逻辑段组织程序,具有代码段、数据段、附加段和堆栈段。完整汇编语言也由段 组成。一个汇编程序语言可以包含若干个代码段、数据段、附加段和堆栈段,段与段 之间的顺序可以随意排列。需独立运行的程序必须包含一个代码段。 对于一般程序来说,太多的段,会增加程序的复杂性,通常需要一个代码段、数据段和 堆栈段 简化段定义的源程序的基本格式如下: .MODEL SMALL----定义程序的存储模型(一般采用SMALL) .STACK----定义堆栈段 .DATA----定义数据段 . . . .CODE----定义代码段 .STARTUP----程序起始点,并建立DS、SS内容 . . . ----程序代码 .EXTI 0----程序结束点,返回DOS . . . ----过程代码 END----汇编结束 其中,SMALL表示小型模型,一个程序最多只能有一个代码段和一个数据段 .STARTUP伪指令产生程序开始执行的代码,同时指定程序开始执行的起始点。 在DOS下,该语句还将初始化DS,调整SS和SP值。 例如:在8086CPU,.STARTUP将汇编成如下启动代码: MOV DX,DSEG----DSEG表示数据段的段地址 MOV DS,DX----设置DS MOV BX,SS SUB BX,DX SHL BX,1 SHL BX,1 SHL BX,1 SHL BX,1 CLI----关中断 MOV SS,DX----调整SS=DS,这是SMALL模型设定 ADD SP,BX STI----开中断 .EXIT程序终止伪指令,产生“终止程序执行返回操作系统”的代码,通常用参数0表示 没有错误。例如,EXIT 0对应的代码为: MOV AX,4C00H----MOV AH,4CH MOV AL,00H INT 21H INT 21H的子功能号4CH,END汇编结束伪指令指示汇编程序MASM到此结束汇编过程。 例子:一个完整的源程序:信息显示程序Infor.asm .MODEL SMALL .STACK .DATA STRING DB 'HELLO,EVERYBODY',0DH,0AH,'$'----在数据段定义要显示的字符串 .CODE .STARTUP MOV DX,OFFSET STRING---- MOV AH,9---- INT 21H .EXIT 0 END 将Infor汇编、连接后得到Infor.exe,在CV.exe中打开。 例子:一个包含子过程的完整源程序 .MODEL SMALL .STACK .DATA .CODE CALL PROC1 .STARTUP .EXIT 0 ;子程序 PROC1 PROC----过程属性默认为NEAR PUSH AX----保护AX、DX PUSH DX MOV DL,0DH----回车的ASCII为0DH MOV AH,2 INT 21H MOV DL,0AH----换行的ASCII为0AH MOV AH,2 INT 21H POP DX----恢复AX、DX POP AX RET----子程序返回 PROC1 ENDP----子程序结束 END 四、汇编语言程序的开发 1.MASM支持80X86汇编以及Win32Asm。MASM必须在Windows下开发。 MASM常用文件: ML.exe----汇编器 LINK.exe----连接器 CV.exe----调试器CodeView 2.开发过程 (1)源程序编辑(可以在DOS文本编辑器DEIT或Windows记事本) 例子:编辑demo.asm,实现 z=x+y,x=36,y=64 记事本内容 .MODEL SMALL .STACK .DATA X DB 36 Y DB 64 Z DB ? .CODE .STARTUP MOV AL,X ADD AL,Y MOV Z,AL .EXIT 0 END (2)源文件的汇编 1)进入DOS状态 2)进入汇编程序(ML.exe)所在的目录 32位系统下,CD命令进入 64位系统下,在当前DOS盘符下即可运行ML.exe 3)输入命令参数:ml/c demo.asm 4)如果源程序没错误,生成目标文件(DEMO.OBJ)。否则不会生成,给出错误,修改 源代码 注意:如果仅利用ml.exe实现程序汇编,参数/c(小写c)必须,否则ML.EXE将自动调用 连接程序link.exe进行连接,其命令为:ml demo.asm。汇编连接成功,得到demo.obj 和demo.exe (3)目标文件的连接 1)DOS下,进入连接程序所在的目录 2)输入命令:link demo.obj 3)无错误,连接过程结束,生成exe文件。如果出现错误报告,不用理会。 ml可以自动调用LINK,实现汇编和连接依次进行,其命令格式为: ML DEMO.ASM (4)可执行文件的运行 在DOS下输入可执行文件。在windows下可能只是一闪。 (5)可执行文件调试CV #################################################### ###############第九章:程序设计(调试)################## 一、顺序程序 例子:求0~7某个整数的平方,设该数和结果均存放在内存中 分析:0~7的整数及平方,均可以用一个字节表示。因此需要定义两个字节变量x和y, 分别存放已知的数(比如5)和结果。用乘法实现求平方,用无符号数乘法 MUL指令计算。 例程: 9_1.asm .MODEL SMALL .STACK .DATA x DB 5 y DB ? .CODE .STARTUP MOV AL,x MUL AL MOV y,AL .EXIT 0 END 二、分支结构 例子:计算 | 1 X>0 Y=| 0 X=0 | -1 X<0 分析:X的值为带符号数,选择带符号数的条件转移指令。共分三种情况,要两个条 件转移指令:判断玩完X>=0后,用JGE指令处理,以分离出X<0的情况;再判断X=0, 还是X>0,用JZ指令处理。 例程:9_2.asm .MODEL SMALL .STACK .DATA X DW ? Y DW ? .CODE .STARTUP MOV X,-2 CMP X,0----判断X>=0? JGE BIN----当X>=0时,转移到BIN MOV Y,-1 JMP NEXT BIN:JZ EQUL MOV Y,1 JMP NEXT EQUL:MOV Y,0 NEXT:.EXIT 0 END 三、循环结构 例子:将BX的值以16进制的形式显示在屏幕上 分析:(1)一个16进制数对应4个二进制位。因此,可以用循环结构,从左到右每 4个二进制位为一组,依次求得对应的16进制,循环次数为4次。显示一个 16位进制前,必须将其对应的4个二进制位移到低位,再转换程ASCII码。 (2)由于0~9的ASCII码是30H~39H,A~F的ASCII码是41H~46H, 所以0~9的数,加30H;否则加37H (3)显示功能采用2号功能。 例程:9_3.asm .MODEL SMALL .STACK .DATA .CODE .STARTUP MOV BX,1234H----BX中存放要显示的值 MOV CX,4----设置循环次数 NEXT:PUSH CX MOV CL,4 ROL BX,CL----循环左移,将高位移至低位 MOV DL,BL AND DL,0FH----取出低位的值 CMP DL,0AH----判断其值是在0~9,还是A~F JL DISP ADD DL,7----做加法 DISP:ADD DL,30H----显示 MOV AH,2 INT 21H POP CX LOOP NEXT .EXIT 0 END ####################################################