1.65k likes | 1.96k Views
第四章 汇编语言程序设计. 一 汇编语言上机过程 二 汇编语言程序结构 三 指示性语句 四 BIOS 和 DOS 功能调用 五 汇编语言程序设计. 上机环境. 用户开发的程序: ABC.exe 等. 操作系统: DOS 系统 编辑器 : EDIT.exe 汇编程序 : MASM.exe 连接程序 : LINK.exe 调试程序: DEBUG.exe. 应用软件. 系统软件. 硬件. CPU 、存储器 (ROM 、 RAM) 、 I/O 接口、输入、输出设备. EDIT. ABC.ASM. 编辑源程序.
E N D
第四章 汇编语言程序设计 • 一 汇编语言上机过程 • 二 汇编语言程序结构 • 三 指示性语句 • 四BIOS和DOS功能调用 • 五 汇编语言程序设计
上机环境 用户开发的程序:ABC.exe等 操作系统:DOS系统 编辑器:EDIT.exe 汇编程序: MASM.exe 连接程序:LINK.exe 调试程序:DEBUG.exe 应用软件 系统软件 硬件 CPU、存储器(ROM、RAM)、I/O接口、输入、输出设备
EDIT ABC.ASM 编辑源程序 MASM ABC.ASM 汇编源程序 Y 有汇编错误信息 ? N ABC.OBJ 形成目标程序 连接目标程序 LINK ABC.OBJ Y 有连接错误信息 ? N 形成可执行程序 ABC.EXE 装入可执行程序到内存 , 并执行 D:\>sub>ABC Y 运行结果正确 ? 下一程序 N N DEBUG ? 用 调试程序查错 Y DEBUG 用 调试可执行程序 找到原因 D:\>sub> DEBUG ABC.EXE 一 汇编语言上机过程 D:>EDIT ABC.asm D:>MASM ABC; 有语法错,回EDIT下改该程序 D:>LINK ABC; 有错,回在EDIT下改程序 D:>ABC 运行结果错,回EDIT下改程序 或在DEBUG下调试,找原因。 D:>DEBUG ABC.exe
二 汇编语言程序结构 • (一)程序结构 • (二)语句结构
(一)程序结构 • 程序由数条语句构成,每条语句占一行。 • 指令性语句(指令语句) • 指示性语句(伪指令语句) • 分段结构 • 程序按段编写, 与8088内存分段编址相对应。 • 每段由伪操作SEGMENT开始、由ENDS结束。 • 程序最后为END结束语句,后跟一启动地址。 • 启动地址指示程序开始执行的第一条语句。 • 程序中设有返回DOS的功能。 • 使程序执行完后返回DOS系统的命令接受状态。 • 程序中用到内存操作数时, • 应按操作数的寻址方式,给相应的段寄存器赋值 ;汇编语言程序结构例一 movs.asm ;实现数据传送功能 aa SEGMENT;数据段1 str1 DB 'Hello!’ aa ENDS bb SEGMENT;数据段2 str2 DB 6 dup (?) bb ENDS cc SEGMENT;代码段 ASSUME CS:cc, DS:aa, ES:bb start: CLD MOV AX , aa MOV DS , AX LEA SI , str1 MOV AX , SEG str2 MOV ES , AX MOV DI ,OFFSET str2 MOV CX , 6 REP MOVSB MOV AH , 4CH INT 21H;返回DOS cc ENDS END start ;指示程序结束
程序可由多个段构成,至少有一个代码段 ;汇编语言程序结构例(子程结构) scans.asm ;用二进制显示中断向量表中(0:0~0:3FFH)数据D0H的个数 • key EQU 0D0H ;用符号表示常量(关键字) • code SEGMENT ;代码段开始 • ASSUME CS:code • begin: MOV AX , 0000H • MOV DS , AX • MOV SI , 0000H • MOV CX , 0400H • MOV BX , 0 • MOV AL , key • next: CMP [ SI ] , AL • JNZ point • INC BX • point: INC SI • LOOP next • CALL display ; 调用显示子程 • MOV AH, 4CH ; 返回DOS • INT 21H • ;用二进制显示BX内容子程 • display PROC • MOV CX , 16 • rotate: ROL BX , 1 • MOV DL , BL • AND DL , 01H • ADD DL , 30H • MOV AH , 2H • INT 21H • LOOP rotate • RET ;子程返回 • display ENDP • code ENDS ;代码段结束 • END begin ;指示程序结束和 • ;程序入口
完整汇编语言程序框架 STACK SEGMENT STACK ;定义堆栈段 DW 512 DUP (?) ;堆栈段有512字(1024字节)空间 TOP LABEL WORD STACK ENDS ;堆栈段结束 DATA SEGMENT ;定义数据段 STRING DB ’HELLO, EVERYBODY !’,0DH,0AH,’$’ DATA ENDS CODE SEGMENT ’CODE’ ;定义代码段 ASSUME CS:CODE,DS:DATA,SS:STACK START: MOV AX,DATA ;建立DS段地址 MOV DS,AX MOV DX,OFFSET STRING MOV AH,9 INT 21H MOV AH,4CH INT 21H ;利用功能调用返回DOS CODE ENDS ;代码段结束 END START ;汇编结束,同时指明程序起始点
可执行程序的结构 • DOS操作系统支持两种可执行程序结构 • 1. EXE程序 • 程序可以有多个代码段和多个数据段,程序长度可以超过64KB • 通常生成EXE结构的可执行程序 • 2. COM程序 • 只有一个逻辑段,程序长度不超过64KB • 需要满足一定条件才能生成COM结构的可执行程序(MASM 6.x需要采用TINY模式)
(二)语句结构 例: data SEGMENT ;数据段 var DB ? data ENDS code SEGMENT ;代码段 ASSUME CS:code,DS:data start: MOV AX, data MOV DS , AX MOV var, CL MOV AH , 4CH INT 21H ;返回DOS code ENDS END start
data SEGMENT ;数据段 var DB ? data ENDS code SEGMENT ;代码段 ASSUME CS:code,DS:data start: MOV AX, data MOV DS , AX MOV var, CL MOV AH , 4CH INT 21H ;返回DOS code ENDS END start • 1. 名字项 • 据语句功能的不同, 名字项可用来表示段名、变量名、 标号、过程名以及常量名等。
名字项用一个符号表示。 • 对符号的规定: • ①由字符A~Z ,a~z ,0~9及符号@、$、下划线_ 等组成, • 最长31个字符,超出部分忽略。 • ② 不能用数字打头,以免与十六进制数相混。 • ③ 不使用汇编程序中的保留字。 (如指令的助记符等) • ④对定义的符号不区分大小写。
汇编语言中的保留字 • 保留字(Reserved Word) • 是汇编程序已经利用的标识符(也称为关键字),主要有: • 指令助记符——例如:MOV、ADD • 伪指令助记符——例如:DB、DW • 操作符——例如:OFFSET、PTR • 寄存器名——例如:AX、CS • 预定义符号——例如:@data • 汇编语言大小写不敏感
2. 助记符项 • 助记符可以是指令、伪操作中的助记符。 • 对于指令,汇编程序将其翻译成机器语言指令。 • MOV AX, 100 → B8 00 01 • 对于伪操作,汇编程序据其要求的功能进行处理。 • data SEGMENT→ data与一段值对应 • string DB ‘Tsinghua’ → string与一内存地址对应
3.操作数项 • 操作数给出参与操作的数或数所在的地方。 • 操作数多于一个时,用逗号分开。 • 操作数可以是常数、寄存器、存储器操作数、 • 标号名、过程名或表达式等。
常数 • 给出具体的数据。可以是数字常量或字符常量。 • ◢ ◢数字默认十进制,也可加D表示十进制数。如1234D, 1234 • ◢◢数字后加B表示二进制数。 如1010B • ◢◢数字后加H表示十六进制数。 如 1234H • ◢◢字符常量,用单引号表示。 如 ‘1234’ • 汇编时,用字符对应的ASCII表示。如31H, 32H, 33H, 34H 例data1 DB 12, 34, 56 ;十进制 data2 DB 12H, 34H, 56H ;十六进制 MOV AL, ‘G’ ;字符 string DB ‘1234’ ;字符串
A、B、C、D、E、F开头的十六进制数前面加0, • 与H结尾的标识符区别。 • 如 寄存器名AH、BH、CH、 DH • 变量名 abcdH 等 • 例 mov AL, 0AH • mov AL, AH • mov BX, 0abcdH
4.注释项 • 由分号引出,用来说明语句或程序的功能。 • 汇编程序对分号后的内容不做处理。 • 作用:①注释程序,增强程序可读性。 • ②可放在语句最前,暂时注释某语句,调试程序用。 • 例、、、 • ; MOV AH, 2 ;显示提示信息 • ; MOV DL, ’A’ • ; INT 21H • 、、、
表达式及运算符 • 有以下几类: • 1. 算术运算符 ( +、-、*、/、MOD ) • 2. 逻辑运算符 ( AND、OR、NOT、XOR ) • 3. 关系运算符 ( EQ、NE、GT、GE、LT、LE ) • 真:FFFFH; 假: 0 • 4. 类型操作 ( PTR ) • 5.数值返回操作符 ( SEG、OFFSET ) • 6. 地址记数器( $ )
例: • 1. 算术运算符 ( +、-、*、/、MOD(取余数) ) • MOV AX, 6 * 8 ← MOV AX, 48 • 2. 逻辑运算符 (AND、OR、NOT、XOR) • MOV AX, 80h OR 70h ← MOV AX,0F0h • 3. 关系运算符 ( EQ、NE、GT、GE、LT、LE ) • 真:FFFFH; 假: 0 • MOV AX, 1 GE 2 ← MOV AX, 0
属性操作符及表达式 4.PTR操作符 格式:类型 PTR 表达式 功能:重新定义已定义的变量或标号的类型。 例如:若定义的变量DATA2为字型变量,则可以有 MOV BYTE PTR DATA2,AL
5.数值返回操作符 (1)SEG、OFFSETTYPE,LENGTH,SIZE SEG 取符号地址的段地址 例 MOV AX , SEG yy OFFSET 取符号地址的偏移地址 例 MOV BX , OFFSET yy bb SEGMENT yy DB 6 dup (?) bb ENDS cc SEGMENT ASSUME CS:cc, DS:aa, ES:bb start: CLD MOV AX , SEG yy MOV ES , AX MOV DI , OFFSET yy MOV CX , 6 ……. cc ENDS END start
MOV AX, bb LEA DI, yy aa SEGMENT xx DB 'Hello!’ aa ENDS bb SEGMENT yy DB 6 dup (?) bb ENDS cc SEGMENT ASSUME CS:cc, DS:aa, ES:bb start: CLD MOV AX , aa MOV DS , AX LEA SI , xx MOV AX , SEG yy MOV ES , AX MOV DI , OFFSET yy MOV CX , 6 REP MOVSB MOV AH , 4CH INT 21H cc ENDS END start D:\>DEBUG hello1.exe -U ;查看程序代码 129F:0000 FC CLD 129F:0001 B89D12 MOV AX , 129D 129F:0004 8ED8 MOV DS , AX 129F:0006 8D360000 LEA SI , [ 0000 ] 129F:000A B89E12 MOV AX , 129E 129F:000D 8EC0 MOV ES , AX 129F:000F BF0000 MOV DI , 0000 129F:0012 B90600 MOV CX, 0006 129F:0015 F3 REPZ 129F:0016 A4 MOVSB 129F:0017 B44C MOV AH, 4C 129F:0019 CD21 INT 21 、、、、、、 22
注意:SEG、OFFSET只能对符号地址操作 • MOV AX, SEG [BX] • MOV BX, OFFSET [SI] 23
TYPE,LENGTH,SIZE 把一些特征或存贮器地址的一部分作为数值回送。 ·TYPE 格式:TYPE variable 变量则回送该变量的以字节数表示的类型(DB为1,DW为2,DD为4,DQ为8,DT为10) 或 label 标号回送标号类型数值(NEAR为-1,FAR为-2) 例:ARRAY DW 1,2,3 ADD SI,TYPE ARRAY 汇编程序其形式: ADD SI,2 24
·LENGTH 格式:LENGTH variable 对于变量中使用DUP汇编回送分配给变量单元数,其他情况回送1。 例:FEES DW 100 DUP(0) 对于 MOV CX,LENGTH FEES 汇编程序将其形式: MOV CX,100 其他情况 例:ARRAY DW 1,2,3 对于指令 MOV CX,LENGTH ARRAY 汇编程序将使其形式为:MOV CX,1 例:TABLE DB ‘ABCD’ 对于指令 MOV CX,LENGTH TABLE 汇编程序使其形式为:MOV CX,1 25
· SIZE 格式:SIZE variable 回送分配给该变量的字节数LENGTH*TYPE 例:FEES DW 100 DUP(0) MOV CX,SIZE ARRAY 将形成:MOV CX,200 例:TABLE DB‘ABCD’ MOV CX,SIZE TABLE 将形成 MOV CX,1 例:ARRAY DW 1,2,3 MOV CX,SIZE ARRAY 形式 MOV CX,2 LENGTH*TYPE=2 26
其中: TYPE变量的返回值是类型的字节数: DB为1,DW为2,DD为4,DQ为8,DT为10; TYPE标号的返回值是:NEAR为-1,FAR为-2。 LENGTH变量返回DUP分配的单元数,对于其他情况则返回1。 SIZE返回值是:LENGTH和TYPE值的乘积,即变量的字节数。 27
等值定义伪操作 • 格式符号名 EQU 需等值的表达式 • 作用是用符号名等值指定的表达式 • 其中 表达式可以是任何有效的操作数 • 汇编时用语句中的表达式代替程序中符号所在的地方。 • 应用: • 1. 定义符号常量,方便修改程序。 • 2. 某表达式多次出现时,用等值伪操作可以方便编程。 • 3. EQU定义的名称在程序中只能定义一次。 28
地址计数器“$” “$”:表示到目前为止该段已经使用的地址空间 • 例1: 设VAR1地址偏移量为1000H,则: VAR1 DB 100H DUP (?) 之后,$=1100H,因此: ADDR1 DW $ 等价于“ADDR1 DW 1100H”,也等价于“ADDR1 DW ADDR1” • 例2: STRING DB ‘ABC’ LEN DW $-STRING ;LEN的值为STRING的长度
地址对准伪指令 ORG • 格式: ORG 数值表达式 • 功能: 用于指定下一个指令或数据在段内的起始地址 • 例: LAB1: PUSH AX ORG 2000H LAB2: MOV AL,34 则LAB2的地址偏移量为2000H。
4.3 源程序的结构和伪指令 • 1.指示性语句 • 2.指令性语句
指示性语句 • (一)程序开始和结束 • (二)段定义 • (三)变量定义 • (四)ASSUME语句 • (五)表达式中的操作符 • (六)过程定义 • (七)等值定义 • (八)数值回送操作符
指示性语句与指令性语句: • 指令性语句是用指令系统中的指令构成的语句。 • 例MOV AX, BX • 指示性语句是指示汇编程序进行汇编的操作。 • 例 MOV AX, 4 + 8 中的+ • code SEGMENT 中的SEGMENT • MOV BX, OFFSET string 中的OFFSET
指示性语句与指令性语句 • 指令(Instruction)——使CPU产生动作、并在程序执行时才处理的指令 • 硬指令就是处理器指令,与具体的处理器有关、与汇编程序无关 • 伪指令(Directive)——不产生CPU动作、在程序执行前由汇编程序处理的说明性指令 • 伪指令与具体的处理器类型无关,但与汇编程序有关。不同版本的汇编程序支持不同的伪指令 • 指令和伪指令采用易于记忆的符合表达,这就是助记符
指示性语句与指令性语句区别 • 一个程序经汇编,连接和装入内存后,在执行程序之前: • ◢指示性语句的功能已经完成,故又称伪操作。 • ◢而指令性语句的功能尚未完成,需控制CPU去执行,才能完成。
(一)模块定义和程序结束伪操作 • 1 . NAME 和 TITLE 伪操作 • 格式NAME模块名 • 格式TITLE模块名 • 在源程序开始可用 NAME 或 TITLE 为模块命名, • 模块名的作用是指示给连接程序进行连接用。 • 源程序中可无模块定义,此时源文件名作为模块名。
2. END伪操作 • 格式END 启动地址 • 作用是指示源程序到此结束。 • 汇编程序对 END 之后的语句不进行处理。 • 程序中所有有效语句应放在 END 语句之前。 • 源程序中必须有 END 结束语句。 • 汇编程序对无 END 语句的源程序不进行处理, • 只给出无 END 语句错误信息。
启动地址可是一个标号或过程名, 指示程序的入口。 • 程序装入内存后,系统跳转到入口处, 开始执行程序。 aa SEGMENT ;数据段1 str1 DB 'Hello!’ aa ENDS bb SEGMENT ;数据段2 str2 DB 6 dup (?) bb ENDS cc SEGMENT ;代码段 ASSUME CS:cc ASSUME DS:aa, ES:bb start: CLD MOV AX , aa MOV DS , AX LEA SI , str1 MOV AX , SEG str2 MOV ES , AX MOV DI , OFFSET str2 MOV CX , 6 REP MOVSB MOV AH , 4CH INT 21H cc ENDS END start D:\masm>DEBUG hello.exe -U :查看代码段 129F:0000 FC CLD 129F:0001 B89D12 MOV AX , 129D 129F:0004 8ED8 MOV DS , AX 129F:0006 8D360000 LEA SI , [0000] 129F:000A B89E12 MOV AX , 129E 129F:000D 8EC0 MOV ES , AX 129F:000F BF0000 MOV DI , 0000 129F:0012 B90600 MOV CX , 0006 129F:0015 F3 REPZ 129F:0016 A4 MOVSB 129F:0017 B44C MOV AH , 4C 129F:0019 CD21 INT 21 、、、 -D 129d:0 l10 ;查看数据段1的内容 129D:0000 48 65 6C 6C 6F 21 00 00-00 00 00 00 00 00 00 00 Hello!.......... -D 129e:0 l10 ;查看数据段2的内容 129E:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ -
(二)段定义伪操作 段名 SEGMENT【定位类型】 【 组合类型】 【 '类别'】 ... ;语句序列 段名 ENDS 【定位类型】 指定逻辑段在主存储器中的边界,缺省时为PARA。 BYTE 段开始为下一个可用的字节地址(xxxx xxxxB) WORD 段开始为下一个可用的偶数地址(xxxx xxx0B) PARA 段开始为下一个可用的节地址(xxxx 0000B) PAGE 段开始为下一个可用的页地址(0000 0000B)
源程序的结构和伪指令 段定义伪指令 【 组合类型】 指定多个逻辑段之间的关系 PRIVATE 私有段,不与其他模块同名段合并。 PUBLIC 同名同类型的段相邻地连接在一起, 合成一个物理段。 STACK 堆栈的段组合类型,所有STACK段 按PUBLIC 方式进行合并。 COMMON 各模块同名段重叠,形成一个段, 起始地址相同时会产生覆盖。
源程序的结构和伪指令 段定义伪指令 【 ‘类别’】 当连接程序组织段时,将所有的同类别段相邻分配。 可以是任意名称,但必须位于单引号中; 大多数MASM程序使用‘CODE’、‘DATA’和‘STACK’ 来分别指明代码段、数据段和堆栈段。
数据传送源程序: 程序经汇编、连接后,装入内存的情况如下: aa SEGMENT ;数据段1 str1 DB 'Hello!’ aa ENDS bb SEGMENT ;数据段2 str2 DB 6 dup (?) bb ENDS cc SEGMENT ;代码段 ASSUME CS:cc ASSUME DS:aa, ES:bb start: CLD MOV AX , aa MOV DS , AX LEA SI , str1 MOV AX , bb MOV ES , AX LEA DI , str2 MOV CX , 6 REP MOVSB MOV AH , 4CH INT 21H cc ENDS END start D:\masm>DEBUG hello2.exe -U :查看代码段 12A0:0000 FC CLD 12A0:0001 B89E12 MOV AX , 129E 12A0:0004 8ED8 MOV DS , AX 12A0:0006 8D360000 LEA SI , [0000] 12A0:000A B89F12 MOV AX , 129F 12A0:000D 8EC0 MOV ES , AX 12A0:000F 8D3E0000 LEA DI , [0000] 12A0:0013 B90600 MOV CX , 0006 12A0:0016 F3 REPZ 12A0:0017 A4 MOVSB 12A0:0018 B44C MOV AH,4C 12A0:001A CD21 INT 21 、、、 -D 129E:0 L10 ;查看数据段1的内容 129E:0000 48 65 6C 6C 6F 21 00 00-00 00 00 00 00 00 00 00 Hello!.......... -D 129F:0 L10 ;查看数据段2的内容 129F:0000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ -
(三)变量定义伪操作 • 格式变量名 类型助记符 操作数 [ ,操作数 , ... ] • 用来定义程序中所用的内存操作数。 • 其中 变量名指示内存操作数的地址(符号地址) • 类型助记符指示内存操作数的类型(字节、字、双字等) • 操作数指示内存操作数的内容 • 汇编程序将定义的操作数,按其类型分配内存单元数, • 顺序存入变量名指向的内存单元中。 • 常用的类型助记符有: • DB指示其后的操作数为字节类型 • DW指示其后的操作数为字类型 • DD指示其后的操作数为双字类型
例: 定义赋初值的变量 • data SEGMENT • xx DB 1, -1, 0fcH • yy DW 1, -1, 0fcH • zz DD 1,- 1, 0fcH • data ENDS
str1 4C ‘L’ ‘i’ 69 ‘a’ 61 ‘o’ 6F 63 ‘c’ ‘h’ 68 ‘e’ 6E ‘n’ 67 49 ‘I’ str2 4e ‘N’ ‘P’ 50 55 ‘U’ 注意:3个及其以上的字符, 只能用DB定义 str1 DW ‘abcd’ str2 DD ‘abcd’ 54 ‘T’ 3a ‘:’ 0d 0dH 0a 0aH ‘$’ 24 • 例: 定义字符串变量( 只能用DB定义 ) • data SEGMENT • str1 DB ' Liaochen ' • str2 DB 'INPUT:' , 0dH , 0aH ,'$' • data ENDS
操作数可以是用常量、表达式和 ? 表示。 • 常量和表达式表示内存操作数的初始值, 其值应在其定义的类型范围内,否则汇编出错。 • 例aa DB 270 • bb DW 80000 • 用 ?表示不置初始值的内存操作数。 • 例cc DB ? • 可用 DUP 复制操作符定义相同的操作数,其格式为 • 重复次数 DUP( 操作数) • 例ee DB 3 DUP ( 4 ) • 等价于 ee DB 4, 4, 4
例:在DEBUG下查看变量存放情况。 data SEGMENT xx DB 1, -1, 0FCH yy DW 1,- 1, 0FCH zz DD 1, -1, 0FCH str DB 'TsingHua' buf DB 4, ?,4 DUP (?) DB ‘dataend’ data ENDS code SEGMENT ASSUME CS:code ASSUME DS:data start: MOV AX , data MOV DS , AX LEA BX , xx LEA SI , yy LEA DI , zz MOV AH , 4CH INT 21H code ENDS END start
LABEL伪指令 LABEL 类型 定义某变量或标号的类型,具有段属性和偏移属性,不占内存 类型: BYTE、WORD、DWORD、结构名、记录名——变量 NEAR、FAR——标号 NEAR可以省略或缺省,只需保护偏移量。 FAR 需要保护段地址和偏移地址。 例:BARRAY LABEL BYTE AARRAY DW 100 DUP (?)
LABEL • LABEL算是一个符号名定义语句。该语句定义一个指定的符号名,该符号名的段地址和偏移量与下面紧跟存储单元的相应属性相同,但该符号的类型是新指定的 • WBUFFERLABELWORD • BUFFERDB200 DUP(0) • … • NEXT1LABELFAR ; • NEXT: MOVAX, BX • WBUFFER与BUFFER具有相同的段地址和偏移量,但它们的数据类型不同。 • NEXT1和NEXT具有相同的段地址和偏移量,NEXT1是“远”标号,NEXT是“近”标号。
(四)ASSUME伪操作 • 格式ASSUME 段寄存器:段名 [, 段寄存器:段名, … ] • 其中 段寄存器为CS、DS、ES、SS中的一个 • 段名为用伪操作SEGMENT定义过的段名 • 例ASSUME CS: cc , DS:aa • ASSUME 伪操作的作用 • 指示汇编程序指令中用到的标号、过程及变量所在的段。 • 其中 对标号、过程必须用 CS 段寄存器指示 • 对变量可用 CS、DS、ES、SS 段寄存器指示