第4章汇编语言程序设计汇编语言的特点:利用汇编语言可以设计出效率较高的核心底层程序,如设备驱动程序;用汇编语言编写的程序一般比用高级语言编写的程序执行得快,且占内存较少;汇编语言程序能够直接有效地利用机器硬件资源,在一些实时控制系统中更是不可缺少和代替的;学习汇编语言是进行计算机应用系统设计的先决条件。汇编语言的应用70%以上的系统软件是用汇编语言编写的某些快速处理、位处理、访问硬件设备等高效程序是用汇编语言编写的某些高级绘图程序、视频游戏程序是用汇编语言编写的汇编语言是我们理解整个计算机系统的最佳起点和最有效途径主要内容:汇编语言源程序的结构汇编语言的语句与格式伪指令功能调用汇编语言程序设计4.1汇编语言源程序了解:计算机的三种语言源程序的结构汇编语言语句格式计算机设计语言机器语言汇编语言高级语言面向机器的语言机器语言汇编语言高级语言面向算法、过程或对象的语言汇编程序汇编语言源程序用助记符编写源程序的编译程序汇编程序汇编语言源程序机器语言目标程序汇编语言程序设计与执行过程输入汇编语言源程序源文件.ASM汇编(编译)目标文件.OBJ链接可执行文件.EXE调试最终程序汇编语言上机过程YYYNNN有错?有错?有错?结束汇编输入(修改)源程序连接运行查错开始用EDIT,NOTEPAD等任何文本编辑器。源程序存为.ASM文件用MASM宏汇编程序进行汇编。汇编后生成.OBJ目标文件。命令格式:MASM源文件名.ASM;用LINK连接程序进行连接。连接后生成.EXE可执行文件。命令格式:LINK目标文件名.OBJ;用TD、DEBUG等调试程序进行调试。命令格式:TD可执行文件名.EXE数据段名SEGMENT…数据段名ENDS附加段名SEGMENT…附加段名ENDS堆栈段名SEGMENT…堆栈段名ENDS代码段名SEGMENT…代码段名ENDSEND4.1.1汇编语言源程序的结构汇编语言的语句有两种:指令性语句——由8086指令助记符构成的语句指示性语句——由伪指令构成的语句指令性语句的格式为:[标号:][前缀]指令助记符[目的操作数,源操作数][;注释]指示性语句的格式为:[名字]伪指令[操作数1,操作数2,…,操作数n][;注释]4.1.2汇编语言的语句与格式各部分之间至少要用一个空格作为分隔符指令性语句由CPU执行,每一条指令性语句都有一条机器码指令与其对应;指示性语句由汇编程序执行。它指出汇编程序应如何对源程序进行汇编,如何定义变量、分配存储单元以及指示程序开始和结束等。指示性语句无机器码指令与其相对应。指令性语句汇编时生成机器码;指示性语句汇编时不生成机器码。语句的构成元素:标号——指令的符号地址,用来代表指令在存储器中的地址。只能出现在指令性语句中,标号后应加上冒号。名字——段、过程、变量的名字,用来代表它们在存储器中的地址。只能出现在指示性语句中,名字后不加冒号。指令助记符——8086助记符、伪指令操作数——即指令的操作对象对指令性语句——0,1,2个对指示性语句——根据需要而定操作数之间以逗号分隔操作数可以是:寄存器、存储单元、常数或表达式例如:AX,[DI+BX+10],200,16*8+TABLE,等等注释——以分号开头,可放在指令后,也可单独一行。注意注解的写法。要写指令(段)在程序中的作用,而不要写指令的操作。例如:以下为同一条指令写的注释1)MOVCX,100;传送100到CX2)MOVCX,100;循环计数器置初值显然,第二种写法要比第一种写法要好。汇编语言的一个实例:hello.asmdataSEGMENTHelloDB‘Hello,world!’,0DH,0AH,’$’dataENDSprogSEGMENTASSUMECS:prog,DS:datastart:MOVAX,dataMOVDS,AXLEADX,hello;取字符串首地址MOVAH,9INT21H;显示字符串MOVAH,4CHINT21H;退回DOSprogENDSENDstart名字标号寄存器存储器单元常量变量或标号表达式4.1.3数据项与表达式常量数字常量字符串常量:用引号引起的字符或字符串例:‘A’,’ABCD’汇编时被译成对应的ASCII码41H,42H,43H,44H标号的属性:段地址:即标号所在段的段地址;偏移量:标号所代表存储单元的段内偏移地址;类型:NEAR或FAR:NEAR—表示标号所在语句与转移指令/调用指令在同一码段内,跳转时只需改变IP即可。FAR—标号所在语句与转移指令/调用指令不在同一代码段内。若没有对类型进行说明,默认为NEAR。标号通常作为转移指令或CALL指令的转移地址。标号变量代表内存中的数据区,程序中视为存储器操作数变量的属性:段值变量所在段的段地址偏移量变量所在段的起始地址到变量地址之间的字节数类型字节型、字型和双字型变量在程序中作为存储器操作数被引用标号和变量名的使用规则组成:A-Z(不分大小写),0-9,?@._$不能以数字开头,圆点(.)只能作为首字符长度小于31个字符不能与保留字(指令助记符、伪指令、预定义符号等)重名不能重复定义例如:正确的:LP1,AGAIN,NEXT,_GO,OK_1错误的:4M,LOOP,AAA,#HELP,+ONE表达式表达式是常数、寄存器、标号、变量与运算符的组合。有数字表达式和地址表达式两种。汇编时按优先规则对表达式进行计算,计算出具体的数值或地址。运行时不能改变。表达式中的运算符有6类:算术、逻辑、关系、取地址、属性、其它类。算术运算符逻辑运算符关系运算符取值运算和属性运算符其它运算符用于数字表达式,例:MOVAX,4*1024汇编后的形式为:MOVAX,4096用于地址表达式,例:LEASI,TAB+3若TAB的偏移地址为1000H,则汇编后的形式为:LEASI,[1003H]算术运算符——+、-、*、/,MOD逻辑运算符只能用于数字表达式中。例:MOVCL,36HAND0FH经汇编后:MOVCL,06H注意,不要把逻辑运算符与逻辑运算指令混淆:例:ANDAX,3FC0HAND0FF00H汇编后源操作数被翻译为:3F00H,所以上述指令与ANDAX,3F00H等价。逻辑运算符——AND、OR、XOR、NOT关系运算的结果是一个逻辑值:真或假关系为真,结果为全1关系为假,结果为全0例:MOVBX,PORTGT300H若PORT的值大于300H,则汇编后为:MOVBX,0FFFFH否则汇编后为:MOVBX,0关系运算符——EQ、NE、LT、GT、LE、GE取值运算符OFFSET取得其后变量或标号的偏移地址SEG取得其后变量或标号的段地址TYPE取变量的类型LENGTH取所定义存储区的长度SIZE取所定义存储区的字节数取值运算符例MOVAX,SEGDATAMOVDS,AXMOVBX,OFFSETDATALEABX,DATA等价于取值运算符例若BUFFER存储区是用如下伪指令定义:BUFFERDW200DUP(0)则:TYPEBUFFER等于2LENGTHBUFFER等于200SIZEBUFFER等于400属性运算符——PTR用来指定地址操作数的类型格式:类型PTR地址操作数类型∈{BYTE,WORD,DWORD,NEAR,FAR}BYTE、WORD、DWORD用于描述数据存储单元(变量)地址NEAR、FAR用于描述转移、调用的目的地址例:MOVBYTEPTR[DI],0;字节类型MOVWORDPTR[DI],0;字类型MOV[DI],0B5H;类型不定PTR也可用来进行强制类型转换例:STR1DW?;STR1定义为字类型MOVAX,STR1;合法MOVAL,STR1;非法MOVAL,BYTEPTRSTR1;合法其它运算符方括号[]方括号中内容为操作数的偏移地址段重设符:段寄存器名:[]用于修改默认的段基地址4.2伪指令由汇编程序执行的“指令系统”用于定义变量、分配存储区、定义逻辑段、指示程序开始和结束等常用伪指令数据定义伪指令符号定义伪指令段定义伪指令结束伪指令过程定义伪指令宏定义伪指令4.2.1数据定义伪指令用于定义数据区中变量的类型格式:[变量名]伪操作操作数[,…];注释某些情况下可省略可选伪指令助记符DB定义的变量为字节型DW定义的变量为字类型(双字节)DD定义的变量为双字型(4字节)DQ定义的变量为四字型(8字节)DT定义的变量为10字节型DATA1DB11H,22H,33H,44HDATA2DW11H,22H,3344HDATA3DD11H*2,22H,33445566H以上变量在内存中的存放形式伪指令的性质决定所定义变量的属性定义字符串必须用DB伪指令例:DATA1DB‘ABCD’,66H‘A’‘B’‘C’‘D’41H42H43H44H66H重复操作符DUP为一个数据区的各单元设置相同的初值格式:[变量名]伪指令助记符nDUP(初值,…)例:DW20DUP(0)DB3DUP(22H,11H,?)随机数用?预留存储空间MEM1DB34H,’A’,?,?,?MEM2DW20DUP(?)预留40个字节单元例:DATA_BDB10,5,10HDATA_WDW100H,-4DATA_DDD0FFFBH汇编后的内存分配情况如右图所示。05H10H00H01HFCHFFHFBHFFH00H00H0AHDATA_BDATA_WDATA_D10510H100H-40FFFBH例:操作数可以是字符串,例如STRDB‘HELLO’汇编后的情况如图:STR‘H’‘E’‘L’‘L’‘O’注意下面两个定义的不同之处:DB‘AB’;41H在低字节,42H在高字节DW‘AB’;42H在低字节,41H在高字节48H45H4CH4CH4FH例:TABLEDB10DUP(?)BUFFERDWTABLE,$+3设TABLE的偏移地址为0080H,则汇编后如下图所示:BUFFER0080H80HTABLE008AH008BH008CH008DH...8FH00H00H0089H10Bytes4.2.2符号定义伪指令把一个表达式用一个符号表示,以后凡出现该表达式的地方都可用这个符号表示。符号定义伪指令有两种:EQU,=用EQU定义的符号未清除前,不能重新定义。清除EQU定义可用PURGE伪指令。用”=”定义的符号可在任何时候进行重定义。二者均不占用存储空间,仅是给符号赋值例:FIVEEQU5COUNTEQUCXTENEQU10DIST=BYTEPTR[SI+BP]GOTO=JMP…MOVAX,TENMOVCX,COUNTADDDIST,FIVEDIST=WORDPTR[SI+BP+1]ADDDIST,AXGOTOLABEL定义引用4.2.3段定义伪指令说明逻辑段的起始和结束说明不同程序模块中同类逻辑段之间的联系形态汇编语言程序是按段来组织程序和数据的。和存储器的物理段相对应,汇编语言程序中的段称为逻辑段。汇编连接后被映射到物理段中。三类段:代码(程序)、数据、堆栈段定义伪指令:SEGMENT、ENDS、ASSUME、ORG定义一个段的基本格式:段名SEGMENT[定位类型][组合方式][类别]汇编语言语句段名ENDS这两个伪指令总是成对出现,二者前面的段名应一致。SEGMENT说明了一个段的开始,ENDS说明了一个段的结束。对数据段和堆栈段,段中的语句一般是变量定义。对代码段则是指令语句。如:dataSEGMENT指令语句dataENDSSEGMENT和ENDS伪指令ASSUME伪指令在代码段中,还必须明确段和段寄存器的关系,这由ASSUME语句来指定。如ASSUMECS:code,DS:data,ES:data语句中的code和data为段名。这个语句说明:1.CS将指向名字为code的代码段2.DS和ES将指向名字为data的数据段但要注意,ASSUME伪指令只是告知汇编