E N D
一、语句类别 汇编语言的基本语句:指令语句 伪指令语句 宏指令语句 源程序是用汇编的语句编写的程序。 格式为 NAME1 Segment NAME1 ENDS NAME2 Segment NAME2 ENDS ENDS 指令语句格式为 [标号:] 助记符 操作数1, 操作数2 [;注释] • 伪指令语句格式为
[符号名] 定义符 参数1………..参数n [;注释] 宏指令语句格式为 [标号:] 宏指令名 参数1………..参数n [;注释] 1. 标号表示一条指令所在地址, 也是指令语句的地址符号, 最多 允许使用31个字符。不能以数字开头。符号名用在伪指令语句前面, 不是每一条伪指令都必须有一个 符号名的。 2. 助记符及定义符由系统定义。 3. 宏指令名由程序员定义, 但不能用系统已经定义过的符号名。 4. 操作数用于指令语句, 参数用于伪指令和宏指令中。 5. 注释不是汇编语句的必须部分。
一、标记(一)字符集:字母、数字、特殊字符(+、-、*、/、{、;等)。(二)界符 : , < - + > • (三)常量 1.数字常量:二进制数、十进制数、八进制数、十六进制数2.字符串常量:由包含单引号内的1至2个ASCII字符构成。 • (四)标识符 由程序建立的, 由最多31个字母, 数字及字符组成, 且不能 用数字开头。 如 : MY_DATA , SUM • THIS_DONE和THISDONE是不同的。(五)保留字:指令助记符, 伪指令, 寄存器名称。(六)注释二、符号 它是一种标识符, 符合标识符的组成规则。 寄存器、变量、标号、数、其它。(一)寄存器:AX 、AL。
(二)变量 存放在存储单元的操作数是变量, 存储单元的地址符号就是 它们的名字。 任何变量都有三种属性: • 1.段值(segment) 2.偏移量(offset):变量单元地址与段的地址之间的偏移量(16位) 3.类型(type):B(字节)、(W字)、(DW双字)(三)标号 与变量相似, 是存储单元的符号地址。 它在存储单元中存放指令, 变量存放数据。 类型 : FAR(CS、IP) 或 NEAR(IP)(四)数 源程序的常数, 常以符号形式出现,便于修改。 如 Count EQU 100 又如 把端口地址定义为一个符号PORT—VAL PORT—VAL EQU 3(五)其它(伪指令部分)除上述寄存器,变量,标记,数外都是伪指令 segement/ENDS
三、表达式 表达式是由标记、符号通过运算符组合起来的序列。 一个表达式是一个由操作数和运算符组合的序列。 (一)操作数 r , m , im(立即数) 1.常量操作数(-2 -1 , 2 -1), 即(-65535 , +65535) 2.存储器操作数 两种:标号——指令语句符号地址 如 JMP, Call 变量——4种寻址方式--直接 --基址 --变址 --基址加变址 可存放在M中的值 三种属性--段值 --段内偏移量 --类型 (二)运算符 16 16
有以下五种:算术运算符 逻辑运算符 关系运算符 分析运算符 合成运算符1. 算术运算符 mod当算术运算符用于存储器时, 只有当结果有明确的、有意义 的物理解释时才有效。 如 SUM+2 地址加2,而不是内容加2 CYCLE-5 NOT_DONE-GO 同段 而SUM-CYCLE 前者是数据段,后者是码段 在不同段,相减无意义 2. 逻辑运算符 按位操作的AND、OR、OR、NOT。其操作数只能是数字的, 且结果是数字, 存储器操作数不能进
行逻辑运算。 如 NOT 1111 1111=0000 0000又如 1111 0000 1111 0000 OR SUM 无效的IN AL,PORT-VAL OUT PORT-VAL AND OFEH,AL若PORT是-VAL是偶数, “与”后仍是同一端口 若PORT-VAL是奇数, “与”后是PORT-VAL低的下一个端口作为汇编的运算符是在程序汇编时计算,而作为指令的助记符,则在程序执行时计算的.如 AND DX , PORT-VAL AND OFEH程序执行时计算3.关系运算符 相等EQ 不等NE 小于LT 大于GT 小于等于LE 大于等于GE关系运算的两个操作数或者都是数字,或者都是同段存储器地址, 汇编时计算
结果是数值。0——关系假 , 0FFFFH——关系真。 如 mov BX , PORT-VAL LT 5 若PORT-VAL的值<5 , 关系为真, 则汇编程序在汇编程序后产生的语句为 mov BX , OFFFFH 否则 mov BX , 0 一般把关系运算符与逻辑运算组合使用。 又如 mov BX , ((PORT-VAL LT 5) AND 20) OR((PORT-VAL GE 5) AND 30) 若PORT-VAL的值<5 汇编程序为 • mov BX , 20 否则 mov BX , 30
一、符号定义语句 (一)等值语句 EQU 定义一个值、别的符号名、可执行指令 格式 NAME EQU Expression 如 buffer-size EQU 32 count EQU CX 定义为寄存器CX的同义语 CBD EQU ADD 定义为加法 New-port equ port-VAL 在解除EQU以前, 不能重新定义。 (二)等号语句 EMP 能对符号进行再定义 emp=6 , emp=7 , emp=emp+1 (三)解除语句 PURGE 用于已经用的EQU语句的情况下 格式 Purge 符号1 , 符号2 , … , 符号n 用purge解除后的符号可以再定义。 如 purge NEW-PORT NEW-PORT EQU PORT-VAL+2二、数据定义语句
为一个数据项分配存储单元, 且并赋符号名和初值。 如 THING DB ? ; 定义一个字节BIGGER-THING D? ; 定义一个字 BIGGEST-THING DD ? ; 定义一个双字 THING DB 25 ; 一个字节把25放入和 BIGGER-THING DW 4142H; 与THING相联系的 存储单元 同样 biggest-thing DD 12345678H当汇编程序汇编时遇到“?”, 则它仍然为数据项分配相应存 储单元,以便存放指令执行的中间结果,并不产生一个目标码 来初始化存储单元。 78 56 34 12 biggest-thing +1 +1 +1
如 POWERS-2 DB 1 , 2 , 4 , 8 , 16 ALL-ZERO DB 6 DUP(0) DB 100 DUP(0) DB 100 DUP(0) 又如 ALPHA DW 2 DUP(3 DUP((1,2 DUP(4,8),6),0) POWERS-2 1 2 4 8 16 1 4 8 4 8 6 1 4 8 4 8 6 1 4 8 4 8 6 5个
字符串(每个字符用ASCII表示, 为一个字节) 如 EXAM1 DB ‘THIS IS AN EXAMPLE’ 或者 DB ‘ T , H , I , S ’ 字符串的定义必须是DB命令 一个存储单元的类型: • 1.数据字节 SUB DB ? ; 定义一个字节 2.数据字 BIGGER DW ? ; 定义一个字 3.数据双字 BIGGEST DD ? ; 4.NEAR指令单元 5. FAR 指令单元 一个指令单元能出现在JMP或CALL语句中。 若类型是near, 产生一个段内JMP、CALL,2个字节。 若类型是far , 产生一个段间JMP、CALL,4个字节。分析运算符把存储器地址分为5个:
seg • offset type size length 指令所在段的段地址加偏移量 一个存储单元地址加或减形成的新的存储单元与原来的存储 单元有相同的类型。seg 功能:可用seg返回变量或标号所在段的段基址。 如 mov AX, seg ABC 把变量ABC的段地址AX offset 功能:offset可返回变量或标号的所在段的偏移量。 type 功能:返回一个表示变量或标号类型的数值。 变量 标号 DB 1 NEAR -1 DW 2 DD 4 FAR -2
如 ALFA DW 20 DUP(?) mov AL , type ALFA ; (2AL)Length 分配单元长度操作符 功能:返回给该变量的单元数 仅对DUP项返回变量单元数,对其它情况均返回值1。 如 ALFA DW 20 DUP(?) BATA DB 12 mov AL, Length ALFA; (20 AL) mov AH, Length BATA; (1 AH) size功能:返回分配给该变量的字节单元数。 如 mov AL , size ALFA ; (40 AL) mov AH , size BATA ; (1 AH) 显然size ALFA=(Length ALFA)*(type ALFA) 合成运算符(PTR、THIS) type PTR variableconstant expression
在PTR左边的操作数有3种:byte , word , Dword。 在PTR右边的操作数生成与原存储器操作数段地址、段内偏 移量相同, 类型不同的新的存储器操作数。 如 OPER1 DB 1 , 2 OPER2 DW 1234H , 5678Hmov AX , OPER1+1 mov BL , OPER2 请考虑一下指令中的斜体部分是否表示正确 正确的应该改为 mov AX , WORD PTR OPER1+1 mov BL , BYTE PTR OPER2对于 mov AX , WORD PTR OPER1+1 OPER1+1的内容AX , 即OPER1+1的内容AL 02 AL 所以(AX)=3402H
而对于 mov AL , BYTE PTR OPER2 把OPER2的第一个字节的内容BL , (AL)=34HTHIS与PTR类似 其段地址加上段内偏移量就是汇编时当前值 • 段地址 + 段内偏移量 • WBUFFER1 EQU THIS WORD BUFFER2 EQU THIS BYTE DWBUFFER3 EQU THIS DWORD • 三、段定义语句 它的主要命令有4个:segment ENDS assume 定义CS、ES是什么段 org 规定段内的起始地址 下面我们来看一个例子: my_DATA segment x DB?
y DW? z DD? My_DATA ENDS my_EXTRA segment ALPHA DB? BETA DW? GAMMA DD? my_EXTRA ENDS my_stack segment DW 100 DUP(?) TOP EQU THIS WORD my_stack ENDS my_CODE segment assume CS:my_CODE , DS:my_DATA • ES:my_EXTRA , SS:my_stack
start : mov AX , seg x mov DS , AX mov AX , seg ALPHA mov ES , AX mov AX , my_stack mov SS , AX mov SP , offset TOP my_CODE ENDS END start 在汇编语言的源程序中,定义CS、SS、DS、ES每一个段必须 有一个名字。一个段由命令segment开始, ENDS结束,成对出现。 最后用END结束源程序。四、过程定义语句 在8088中调用过程和返回的指令是call和ret过程定义语句。 PROC和ENDP是在说明call和ret是NEAR还是FAR型。 如 procedure_name proc [NEAR]
. ret procedure_name ENDP谨记proc和ENDP成对出现。 一个过程定义的例子:my_code segment my_code ENDS up_count proc near END ADD CX,1 RET up_count ENDP start : call up_count call up_count
五、结束语句segment—ENDS proc—ENDP END END <表达式> 表达式为第一条要执行的指令的地址
指令助记符 指令前缀 操作数寻址方式 串操作指令一、指令助记符 (一)NOP:保留一些单元为以后填入指令时用,放慢速度。 (AX自行交换) (二)NIL:保留空格 如 CYCLE:NIL CYCLE: INC AX INC AX二、指令前缀 1.段超越:由assume语句的信息选择段寄存器。 如 mov BX , ES :SUM • 由汇编程序决定在用选择的 段寄存器是否超越 2.重复:rep repE 当相等时重复 repNE 当不相等时重复 指令语句
repZ Z=1时重复repNZ Z=0时重复3.锁定:LOCK三、操作数寻址方式 共有8种:立即 寄存器 直接 基址 变址 基址变址 基址或变址+位移量 基址变址+位移量 • 如 SUM DB ? 字节INC SUM 一个字节增量 如 mov AL , [BX]字节 由目的指定[BX]也是字节型 而 INC [BX] 是错误的INC BYTE PTR [BX] 一个字节增量INC WORD PTR [BX] 一个字增量四、串操作指令
请回忆一下之前学过的指令 。COMPS (SI) -(DI) • 指令语句 指示性语句:符号定义、分存储单元、分段 码段 栈段 数据段如两个未压缩的BCD码相加。先数据段、再堆栈段、码段 DATA segment stri1 DB ‘1’ , ‘7’ , ‘5’ , ‘2’ stri2 DB ‘3’ , ‘8’ , ‘1’ , ‘4’ count equ $-stri2 $表示当前地址计数的值 MOVS (DI) (SI) DI1,2 SI 1,2SCAS AL/AX-(DI) DI1,2 SI 1,2 LODS AL/AX(SI) SI 1,2STOS AL/AX(DI) DI 1,2 源程序 程序 关于$
DATA ENDS stack segment stack para stack ‘stack’ stapN DB 100 DUP(?) TOP EQU Length stapN stack ENDS CODE segment assume CS:code , SS:stack , DS:DATA , ES:DATA start proc FAR PUSH DS mov AX , 0 PUSH AX go: mov AX , DATA mov DS , AX mov ES , AX mov AX , stack mov SS , AX mov AX , TOP mov SP , AX 在堆栈中推入一个段地址DS和IP 返回DOS
CLC CLD mov SI , offset stri1 mov DI , offset stri2 mov CX , count cycle: LODS stri1 ADC AL , [DI] AAA STOS stri2 LOOP cycle RETSTART ENDPCODE ENDS END start 定义数据 , 堆栈段 , 代码段 , 过程定义语句。 RET返回DS , IP(0000H) DOS源——目标——连接——程序前缀
一、概述 1.汇编语言源程序的结构 NAME 数据段名 segment 变量定义 数据空间预量 数据段名 ENDS 堆栈段名 segment para stack ‘stack’ 堆栈空间预量 堆栈段名 ENDS 代码段名 segment assume段寄存器地址说明 start : 段地址装填 主程序 过程名1 proc类型 过程体 过程名1 ENDP
过程名N proc类型 过程体N过程名N ENDP代码段名 ENDS END start2. 段寄存器的装填 CS由系统在加载程序后由系统自动装填 SS也可以由系统自动装填 , 但必须将参数写全 如stack、segment、para、stack、‘stack’当程序装入内存时,系 统把堆段地址和栈指针置入SS和SP ,因而不必在代码段装填SS 和SP。 DS、SS、ES的装填 mov AX , 数据段名 mov DS , AX3.返回DOS DOS下运行汇编程序 , 当程序执行结束后返回DOS。 过程名 proc far push DS
mov AX , 0 push AX ret 过程名 ENDP ENDP 过程名 (INT 20H)是返回DOS的系统调用 , 系统将执行INT 20H 系统(装入程序时)放在程序段前缀的头二个字节 (100H字节的信息区, 放在程序段前) 当执行程序后 , DS和偏移量CS、IP, 从而执行INT 20H4.编写程序步骤(1)建立数学模型 • (2)确定解决模型的算法 (3)画流程图 工作框 : 一个入口,一个出口 判断框 : 一个入口,几个出口
子程序框: 一个入口一个出口 程序走向: • (4)分配内存单元和寄存器(5)写程序二、直线运行程序 两个32位无符号数乘法 A B AD 16位 C D BC BD AC + 最后乘积
name data segmentmulnum dw 0000 , ffff , 0000 , ffff , 4 dup(?) data ends stack segment para stack ‘stack’ • db 100 dup(?) stack ends code segment assume cs:code , ds:data , ss:stack , es:data start proc far being: push ds ; mov ax , 0 push ax mov ax , data mov ds , ax mov es , ax lea bx , mulnummulu32: mov ax , [bx] ; BAX DS中包含的是程序段前的起始地址 设置返回至DOS的段值和IP值 置段寄存器初值
mov si , [bx+4] ; D SI mov di , [bx+6] ; C DI mul si BD (DX , AX) mov [bx+8] , ax mov [bx+a] , dx mov ax , [bx+2] A AX mul si ; AD(DX , AX) 乘积2 add ax , [bx+a] adc dx , 0 mov [bx+a] , ax mov [bx+c] , dx mov ax , [bx] B AX mul di B C(DX , AX) 乘积3 add ax , [bx+a] 与乘积3的相应部分积相加adc dx , [bx+c] mov [bx+a] , ax mov [bx+c] , dx pushF 保存C(保存后一次相加的进位) 保存乘积1 乘积2与乘积1的相应部分相加 乘积3与乘积2的相应部分相加
mov ax , [bx+2] AAX mul di AC(DX , AX) 乘积4 popF adc ax , [bx+c] 与乘积4相应部分相加adc dx , 0 mov [bx+c] , ax mov [bx+e] , dx ret start endP code ends end beginP127 例: 32位有符号数乘法 name data segment • sign db ?mulnum dw X1 , X2 , X3 , X4 , 4 dup(?) data ends
stack segment para stack ‘stack’ db 100 dup(?)code segment assume cs:code , ds:data , ss:stack , es:datastart proc farbegin:push ds mov ax , 0 push ax mov ax , data mov ds , ax mov sign , 0 置符号初值 lea bx , mulum mov ax , [bx] B AX mov dx , [bx+2] A DX mov si , [bx+4] D SI mov di , [bx+6] C DI cmp dx , 0 检验正、负 jns other 若为正(即S=0)转至other 返回至DOS
not ax not dx add ax , 1 adc dx , 0 not sign 改变符号 mov [bx] , ax mov [bx+2] , dxother: cmp di , 0 检验乘数符号 jns go mul 若S=0则转移到go mul not si not di add si , 1 adc di , 0 not signgo mul: call mulu32 调用无符号乘数 cmp sign , 0 检验S位 je done Z=1(相等)乘积为正 , 结束 not word ptr [bx+8] 若为负则求补 保存被乘数 乘数求补
not word ptr [bx+a] not word ptr [bx+c] not word ptr [bx+e] add word ptr [bx+8] , 1 adc word ptr [bx+a] , 0 adc word ptr [bx+c] , 0 • adc word ptr [bx+e] , 0 done: ret start endPmulu32三、分支程序设计 • ( P129 ) <0 >0 x =0 y-1 y0 y1 出口 乘数求补 1 X>0 y= 0 X=0 -1 X<0
sigef mov AX , buffer OR AX , AX 执行一个判断 JE ZERO Z=1 转移至zero JNS plusS=0 转移至plus mov BX , FFFFH y-1 JMP conti zero : mov BX , 0 JMP conti plus : mov BX , 1 conti :例:数据AL的被置位的情况控制转移到8个子程序中。 AL : 0000 0001 0000 0010 0000 0100 0000 1000 0001 0000 0010 0000 0100 0000 1000 0000 R1R2R3R4R5R6R7R8
name data segment brtab dw R11 子程序R1入口地址的IP值dw R12 子程序R1入口地址的码段值dw R21 同上dw R22 同上 • dw R81 dw R82 data ENDSstack segment para stack ‘stack’ DB 100 DUP(?)TOP equ $-STACKstack endscode segmentstart proc far assume cs:code , ds:data , ss:stack , es:data begin : push DS 启动 Y R1 D0=1? Y N R2 D1=1? N Y R7 R8
mov AX , 0 push AX mov AX , data mov DS , AX mov AX , stack mov SS , AX mov AX , TOP mov SP , AX lea BX , brtab 设跳转地址的地址指针gtbit: RCR AL , 1 JC getad C=1时转移 INC BX INC BX INC BX INC BX JMP gtbitgetad:JMP Dword ptr [BX] ;段间间接转移 start ENDP C BXBX+4
四、循环程序设计 • 例1.用计数器控制循环 寻找一串给定个数的数中的最大值,并放入指定单元中。 每个数用16位表示。 name data segment buffer dw X1 , X2,…, Xn count equ $-buffer max dw ? data endsstack segment para stack ‘stack’ 工作部分 控制部分 循环体 结构 循环结束条件 循环初态 循环工作初态:如标志位、寄存器清零 结束条件初态:CX的初态
DB 64 (?) top equ $-stackstack endscode segment assume cs:code , ds:data , ss:stack , es:databegin : push DS mov AX , 0 push AX mov AX , data mov DS , AX mov AX , stack mov SS , AX mov AX , top mov SP , AX mov CX , count SHR CX , 1 lea bx , buffer mov AX , [BX]
INC BX INC BX dec cxagain: cmp AX, [BX] • JGE next mov AX , [BX]next: INC BX INC BXLOOP againstart endPcode ENDS END start 例2. 条件控制循环 求16位无符号数的整数平方根 X2=(N/X1X1)/2 X1=(N/200+2) 若X1是数N的平方根的近似值,则X2是数N的平方根的最近 似值,这个称为逐次逼近法
name data segment num dw 2710H result dw ? digit equ 200 data ends stack segment para stack ‘stack’ db 100 dup (?)stack endscode segment assume cs:code , ds:data , ss:stack , es:databegin: mov ax , data mov ds , ax mov ex , ax lea bx , num mov ax , [bx] axN mov si , ax SIN
mov di , digit DI200 cwd 双字扩展 AX(DX , AX) div di N/200 add ax , 2 N/200+2 AX=X1conti: mov cx , ax mov ax , si cwd div cx add ax , cx shr ax , 1 mov dx , ax sub dx , cx je done cmp dx , 1 jne contidone:mov [bx+2] , ax retstart endP Q
code ends end begin3.多重循环 delay : mov DX , 3FFH time : mov AX , FFFFH time1 : dec AX NOP JNE time1 dec DX JNE time ret ————延时程序4.用开关量控制循环 name data segment buffer dw 05…05 , 05…05 block dw 12 dup(?) 第一循环支路 第二循环支路