1.15k likes | 1.4k Views
第 3 章 80x86 汇编语言程序设计 ( 下 ). 3.3 汇编语言格式. 汇编语言源程序结构 汇编语言上机过程 汇编语言语句格式 伪操作(伪指令). 3.3.1 源程序结构概览. 数据段 说明: 堆栈段 1 、各段顺序无关 2 、除代码段外,可缺省 3 、可有若干个数据段, 若干代码段 代码段
E N D
3.3 汇编语言格式 • 汇编语言源程序结构 • 汇编语言上机过程 • 汇编语言语句格式 • 伪操作(伪指令)
3.3.1 源程序结构概览 数据段 说明: 堆栈段 1、各段顺序无关 2、除代码段外,可缺省 3、可有若干个数据段, 若干代码段 代码段 END [标号] 附加段
汇编语言程序例 DATA SEGMENT BUF1 DB 34H BUF2 DB 2AH SUM DB ? DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA START: MOV AX, DATA MOV DS, AX MOV AL, BUF1 ADD AL, BUF2 MOV SUM, AL MOV AH, 4CH INT 21H CODE ENDS END START
3.3.2 汇编语言源程序上机过程 汇编 连接 masm link 源程序 .asm 目标程序 .obj 可执行程序 .exe 结果 debug DOS下执行 执行
3.3.3 汇编语言语句格式 有三类语句: 指令语句——完成操作功能,能翻译成机器代码 伪指令语句——为汇编程序在翻译源程序时提供 有关信息 宏指令语句——由若干条指令语句组成的语句 通用语句格式: [名字] 操作项 [操作数] [;注释]
指令语句格式 [标号:]指令助记符[[目的操作数][,源操作数]][;注释] 其中,[ ]表示可选项; 1、标号 标号是后续指令的符号名称,可用符号是: 字母:A--Z, a--z 数字符: 0--9 专用字符:?, _, @, $ 标号长度不超过31个字符 2、指令助记符 指令助记符是汇编指令的符号代码,不可缺省。 汇编源程序时,系统使用内部对照表将每条指令的 助记符译成相应的机器码。
3、目的操作数 1)参与指令操作 2)暂存操作结果 除立即寻址方式外,其他寻址方式均适用于目的操作数. 4、源操作数 提供原始数据或操作对象,面向所有寻址方式 5、注释 注释在系统汇编时并不产生机器码 注释可以放在指令语句尾,也可单独使用 注释前面的“;”不可缺少
常量 常量有两种: 1、数值常量 二进制数 以B结尾,如01011101B 八进制数 以Q结尾,如235Q 十进制数 以D结尾或没有结尾字母,如98D或98 十六进制数 以H结尾,如5BH 2、字符串常量 用单引号括起来的一个或多个字符,如‘A’、’AB’ 字符用ASCII码形式存储 常量的应用: (1)在指令语句中作立即数 MOV CX, 100 (2)在指令语句中作位移量 MOV AX, 34[SI] (3)在数据定义语句中作初值 X DB 12H, 34H
变量和标号 变量有三种属性: 1、段属性——变量所在段的起始地址 2、偏移属性——从段起始地址到定义变量的位置之间的字节数 3、类型属性——该变量所保留的字节数 DB 1个字节 DW 2 个字节 DD 4个字节 DQ 8个字节 DT 10个字节
标号也有三种属性: 1、段属性——定义标号所在段的起始地址 2、偏移属性——从段起始地址到定义标号的位置之间的字节数 3、类型属性——表示它的转移特性 NEAR (近) 段内转移 FAR (远) 段间转移
3.3.4 伪指令 • 处理器选择伪指令 • 数据定义和存储器分配伪指令 • 段定义伪指令 • 程序开始和结束伪指令 • 表达式赋值伪指令 • 地址计数器与对准伪指令 • 基数控制伪指令
(一)处理器选择伪指令 .8086 可使用8086指令(一般不用写) .286 可使用80286指令 .286P 可使用保护方式下的80286指令 .386 可使用80386指令 .386P 可使用保护方式下的80386指令 .486 可使用80486指令 .486P 可使用保护方式下的80486指令 .586 可使用Pentium指令 .586P 可使用保护方式下Pentium的指令 .686 可使用Pentium Pro指令 .686P 可使用保护方式下Pentium Pro的指令 .MMX 可使用MMX指令 .XMM 可使用SSE指令 当源程序使用了286及以上的机型新增加的指令时,应该在程序开始使用相应的处理器选择伪指令。
(二)数据定义伪指令 格式:[变量名] 定义符 操作数项表 操作:为变量分配存储单元并将初值置入相应单元中 定义符可为: DB—— 定义字节 DW ——定义字(2个字节) DD——定义双字(4个字节) DF——定义六字节 DQ——定义八字节 DT——定义十字节 操作数项可为: 1、常数或表达式 2、字符串 3、?表达式 4、带DUP 的表达式 操作数项表: 操作数项[, 操作数项[, 操作数项…]]
操作数是常数或表达式 X1 DB 40H ;为X1分配1个字节,初值40H X2 DW 250*250 ;为X2分配2个字节,初值62500 X3 DD 10203040H ;为X3分配4个字节,初值为10203040H X4 DQ (120+50)/10 ;为X4分配8个字节,初值17 X5 DB 10, 20, 30 ;多项定义,X5被分配3个字节,初值分别为10,20,30,地址从低到高,各个值间用逗号分开
操作数为字符串 STRING1 DB ‘HELLO’ STRING2 DB ‘H’, ‘E’, ‘L’, ‘L’, ‘O’ 字符串用DB定义,被定义串以单引号括起来 串中可包含数字符、大小写英文字母、回车符、 换行符、 空格、?、$、下划线_等 字符串以ASCII码形式存储在存储单元中。 STRING1 ‘H’ +1 ‘E’ +2 ‘L’ +3 ‘L’ +4 ‘O’
区分 S1 DB ‘AB’ 与S2 DW ‘AB’ 它们的存储情况为: S1 S2 ‘A’ ‘B’ ‘B’ ‘A’ 操作数项为? ?用于预留空间,不置初值 Y1 DB 20H, ? ;定义2个字节,其中预留1个字节 Y2 DW ?, ? ;预留2个字 Y3 DD ? ;预留4个字节 Y4 DQ ? ;预留8个字节 Y5 DT ? ;预留10个字节
操作数项带重复定义符DUP 格式:N DUP(操作数项表) 操作:以N所示次数定义操作数项表内容 VAR1 DW 2 DUP(2, 4), 1476H VAR2 DB 2 DUP(?, 2 DUP(‘A’, ‘B’) ) 存储情况为: VAR1 02H VAR2 ? 00H ‘A’ 04H ‘B’ 00H ‘A’ 02H ‘B’ 00H ? 04H ‘A’ 00H ‘B’ 76H ‘A’ 14H ‘B’
操作数运算符 • 算术运算符 • 逻辑运算符 • 关系运算符 • 数值回送运算符 • 属性运算符 • 运算符优先级
算术运算符(单目+, 单目-, +, -, *, /, MOD) 运算符 格 式 运 算 + +表达式 取表达式正值 - -表达式 取表达式负值 + 表达式1+表达式2 求表达式1、表达式2之和 - 表达式1-表达式2 求表达式1、表达式2之差 * 表达式1*表达式2 表达式1、表达式2之积 / 表达式1/表达式2 表达式1、表达式2之商 MOD 表达式1 MOD 表达式2 取余数 说明: 1、算术运算符可用于数值表达式或地址表达式 2、用于地址表达式时,只有其结果有物理意义时才有效 常用的是:地址+数字常量 地址-数字常量
算术运算符示例 (1) MOV AL, 20+30 ;50-->AL MOV BH, 100-2 ;98-->BH MOV CX, 50/2 ;25-->CX MOV AL, 80 MOD 15 ;5-->AL (2) 将首地址为BLOCK的字数组的第6个字传送到DX: MOV DX, BLOCK+(6-1)*2 ; 地址+常量,结果仍为一地址值 (3) 设数据定义如下: ARRAYA DW 1, 2, 3, 4, 5, 6, 7 WENDA DW ? 将数组长度(字数)存入CX: MOV CX, (WENDA-ARRAYA)/2 ; 地址-地址,结果为一常量
逻辑运算符(NOT,AND,OR,XOR) 运算符 格 式 运 算 NOT NOT 表达式 按位取反 AND 表达式1 AND 表达式2 按位“与”运算 OR 表达式1 OR 表达式2 按位“或”运算 XOR 表达式1 XOR 表达式2 按位“异或”运算 逻辑运算符和逻辑运算指令的区别: 逻辑运算指令 逻辑运算符 出现在语句的位置 指令助记符 操作数字段 操作对象 可以是寄存器或 只能是整型常数 存储器操作数 何时计算 程序运行时 源程序汇编时
关系运算符(EQ,NE,LT,LE,GT,GE) 运算符 格 式 运 算 EQ 表达式1 EQ 表达式2 表达式1=表达式2为真 NE 表达式1 NE 表达式2 表达式1<>表达式2为真 LT 表达式1 LT 表达式2 表达式1<表达式2为真 LE 表达式1 LE 表达式2 表达式1<=表达式2为真 GT 表达式1 GT 表达式2 表达式1>表达式2为真 GE 表达式1 GE 表达式2 表达式1>=表达式2为真 关系运算符的两个操作数必须都是常量或同一段内的符号地址,比较结果为逻辑值:如果关系成立,则返回0FFFFH(真);否则,返回0(假)。
逻辑运算符示例 MOV AH, NOT 0F0H;0FH-->AH MOV BL, 40H OR 0B4H;0F4H-->BL XOR BL, 55H XOR 48H;XOR BL, 1DH AND CH, 50H AND 30H;AND CH, 10H 关系运算符示例 N1 EQU 10 N2 EQU 20 ……... MOV BX, N1 EQ N2; 0-->BX MOV CX, N1 NE N2;0FFFFH-->CX MOV AX, N1 LT N2;0FFFFH-->AX MOV DI, N1 GE N2;0-->DI
数值回送运算符 (SEG,OFFSET,TYPE,LENGTH,SIZE) 数值回送运算符对变量或标号进行分析, 回送其地址属性值或变量特征值。 (1)地址回送运算符 符号 作用对象 操 作 SEG 变量或标号 返回其所在段的段基址值 OFFSET 变量或标号 返回其在段内的偏移量
(2)符号特征回送运算符 符号 作用对象 操 作 TYPE 变量或标号 用数字表示其类型属性 LENGTH 变量 用DUP重复定义符定义的变量 ,返回分配的元素个数;其他 形式,则返回1 SIZE 变量 回送LENGTH*TYPE之积
TYPE 运算符 类型属性 运算结果 变量DB 1 DW 2 DD 4 DQ 8 DT 10 标号 NEAR -1 FAR -2
数值回送运算符示例 D_SEG SEGMENT NUM1 DB 10 DUP(10) ;数据定义 NUM2 DB 10H, 20H, 50H NUM3 DW 20 DUP(0, 4 DUP(2)) NUM4 DB ‘STRING’ D_SEG ENDS 注意OFFSET与LEA的区别 MOV AX, SEG NUM1 MOV BX, SEG NUM2 ;NUM2与NUM1段基址值相同 MOV SI, OFFSET NUM1 ;NUM1的偏移量-->SI MOV DI, OFFSET NUM2 ;NUM2的偏移量-->DI MOV AH,TYPE NUM3 ; 2-->AH MOV BH,LENGTH NUM3 ;20-->BH(最外层) MOV CL, SIZE NUM4 ;1*1-->CL MOV CH, SIZE NUM3 ;20*2-->CH
属性运算符 (PTR,SHORT) PTR 格式: 类型 PTR 表达式 操作: 对存储器寻址的表达式,类型可为BYTE,WORD,DWORD, QWORD和TBYTE; 表达式为标号时,类型可为NEAR或FAR。 该运算符显式指定表达式的类型 SHORT 格式: JMP SHORT 标号 操作: 转移的距离属性为短,即转移范围为-128~+127字节
PTR 运算符示例 (1)DATA1 DB 10H, 20H, 30H DATA2 DW 4023H, 1A00H ;数据定义 ...... MOV AX, WORD PTR DATA1 ;(AX)<--2010H MOV BL, BYTE PTR DATA2 ;(BL)<--23H PTR运算符指明DATA1由原来的字节变量临时 改变为字变量,而字变量DATA2则临时变为字节变量, 所谓临时是指在当前指令语句中有效,而存储分配情况 并不改变。 (2) MOV BYTE PTR[SI], 60H ;字节传送 SUBWORD PTR[BX], 36H ;字数据减 JMP FAR PTR S1 ;段间转移
本课件涉及到的运算符优先级 优先级 运算符 类 别 1 LENGTH,SIZE 数值回送运算符 2 PTR,OFFSET,SEG,TYPE, 属性与数值回送运算符 3 +,- 符号运算符 4 *,/,MOD 算术运算,移位运算符 5 +,- 算术运算符 6 EQ,NE,LT,LE,GT,GE 关系运算符 7 NOT 逻辑运算符 8 AND 逻辑运算符 9 OR,XOR 逻辑运算符 说明:优先级1最高,而优先级9最低 圆括号()可改变执行顺序
(三) 段定义伪指令 1) 完整的段定义伪指令 格式:段名 SEGMENT [定位类型][组合类型][使用类型]['类别名'] …... 段名 ENDS 操作:定义逻辑段 (1)定位类型 指定当前段的起始地址的性质 1、PARA 段起始地址的低4位为0H,即16的倍数。 2、PAGE 段起始地址的低8位为00H,即256的倍数 3、BYTE 段可从任意地址开始 4、WORD 当前段的起始地址为偶地址 5、DWORD 段的起始地址为4的倍数 默认项是PARA
(2)组合类型 说明程序连接时的段合并方法 1、PRIVATE 为私有段,连接时不与其他模块中的同名段合并 2、PUBLIC 不同模块的同名段连接在一起,形成参与邻接模块所公用的物理段 3、COMMON 产生一个覆盖段。与其它具有该类型的同名段拥有同一起始地址,共享相同的存储区。共享存储区的长度由同名段中最大的段确定 4、STACK 功能同PUBLIC,但新形成的段为堆栈段 默认项是PRIVATE
(3)使用类型 说明使用16位还是32位寻址方式 USE16 使用16位寻址方式 USE32 使用32位寻址方式 386以下处理器默认项是USE16,386及以上处理器默认项是USE32 (4)‘类别名’ LINK 程序将‘类别名’相同的段依次序连续存放在 内存中。如果这些段未选择PUBLIC、COMMON组合 类型,则这些段将各自独立 缺省‘类别名’,作空处理。
段定义伪指令示例 D_SEG SEGMENT PARA 'DATA' NUM1 DB 10 DUP(?) D_SEG ENDS S_SEG SEGMENT PARA 'STACK' DW 100 DUP(?) S_SEG ENDS E_SEG SEGMENT 'DATA' STRING DB 'HELLO' E_SEG ENDS ....
2)指定段寄存器伪指令 格式: ASSUME 段寄存器:段名[,段寄存器:段名[...]] 操作: 明确段与段寄存器的关系。 说明: 1、代码段中必须至少有一个ASSUME语句 2、ASSUME可以出现在源程序中的任意地方 3、仅说明段与段寄存器的对应关系,除了在程序装入时将代码段和堆栈段的段基址赋值给CS和SS外,并没有把数据段和附加段的段基址值送入DS、ES、GS和FS寄存器中,需要在程序中显式赋值 。
ASSUME语句示例 D_SEG SEGMENT PARA 'DATA' NUM1 DB 10 DUP(?) D_SEG ENDS S_SEG SEGMENT PARA 'STACK' DW 100 DUP(?) S_SEG ENDS E_SEG SEGMENT 'DATA' STRING DB 'HELLO' E_SEG ENDS C_SEG SEGMENT PARA 'CODE' ASSUME CS:C_SEG, DS:D_SEG, ES:E_SEG; SS:S_SEG START: ...... C_SEG ENDS END START 这里明确D_SEG段为数据段,S_SEG段为堆栈段,E_SEG段为附加段,C_SEG为代码段。
段寄存器的赋值 (1)代码段寄存器CS(及IP)的赋值 当连接程序扫描到程序结束伪指令END符号地址时,系统自动将当前代码段基址赋值给CS,同时把END后的符号地址送入IP (2)堆栈寄存器SS(及SP)的填入有以下两种方法: 1、系统自动填入 被定义为堆栈的段选择STACK组合类型,当含有该段的目标程序被装入存储器时,系统自动取该段基址送SS,取段长度送SP 系统自动填入SS示例 S_SEG SEGMENT PARA STACK 'STACK' DW 200 DUP(?) S_SEG ENDS
2、用指令填入 被定义为堆栈的段在组合类型位置上缺省,在代码段中用3条MOV指令完成这个功能. 用指令填入SS示例 S_SEG SEGMENT PARA 'STACK' DW 200 DUP(?) TOP LABLE WORD S_SEG ENDS C_SEG SEGMENT PARA 'CODE' ASSUME CS:C_SEG,SS:S_SEG,DS:NOTHING,ES:NOTHING START: MOV AX, S_SEG ;填入段基址 MOV SS, AX LEA SP, TOP ;填入栈指针 C_SEG ENDS END START
(3)数据段寄存器DS及附加段寄存器的填入 用MOV传送指令填入 填入DS、ES示例 D_SEG SEGMENT PARA ‘DATA’ ;数据段 X DW ?, 4000H, 100 DUP(?) D_SEG ENDS E_SEG SEGMENT PARA ‘DATA’ ;附加段 STRING DB 'EXAMPLE' E_SEG ENDS C_SEG SEGMENT PARA 'CODE' ASSUME CS:C_SEG,DS:D_SEG,ES:E_SEG,SS:S_SEG START: MOV AX, D_SEG MOV DS, AX ;数据段基址-->DS MOV AX, E_SEG MOV ES, AX ;附加段基址-->ES
3)存储模型与简化段定义伪指令 1、模式选择伪指令MODEL 格式:.MODEL 模式选择符 功能:指明简化段所用内存模式 • Tiny模式(微模式):所有数据和代码放入同一物理段内, 可写成 .COM文件形式 • Small模式(小模式):所有数据放在一个64KB的段, 所有代码放在一个64KB的段 • Medium模式(中模式):所有数据放在一个64KB的段, 代码可放在多个段 • Compact模式(压缩模式):所有代码放在一个64KB的段, 数据可放在多个段 • Large模式(大模式):代码和数据都可用多个段 • Huge:与Large相同,但数据段大小可超过64KB • Flat: 允许用户用32位偏移量
2、简化的段定义伪指令 数据段定义伪指令 格式:.DATA [名字] 功能:定义数据段,若有多个数据段,用名字区别。 只有一个数据段时,段名为@DATA 栈段定义伪指令 格式:.STACK [名字] 功能:定义一个栈段,并形成SS及SP的初值,SP的默认值为1024,隐含段名为@STACK 代码段定义伪指令 格式:.CODE [名字] 功能:定义代码段,若有多个代码段,用名字区别。 只有一个代码段时,段名为@CODE
简化段定义示例 .MODEL SMALL .STACK 100H .DATA …… .CODE START: MOV AX, @DATA MOV DS, AX …… MOV AX, 4C00H INT 21H END START
(四)程序开始和结束伪指令 1)程序开始伪指令 格式1: NAME 模块名 操作1: 用此名作为模块名 如缺省则以模块的源程序文件名为模块名 格式2:TITLE 文本 操作2:没有NAME时,用其前6个字符作为模块名 可在列表文件中打印标题 模块命名伪指令示例 NAME MODE1 …… NAME MODE2 …… TITLE EXAM
2)源程序结束控制伪指令 格式1:END 格式2:END 符号地址 功能:告诉汇编程序,源程序到此结束,并将符号地址 所示单元的段基址和偏移量自动装入CS和IP中 源程序结束控制伪指令示例 C_SEG SEGMENT PARA 'CODE' ASSUME CS:C_SEG, …... START: ...... C_SEG ENDS END START 说明: 源程序从标号START处开始执行
(五)表达式赋值伪指令(EQU,=) 格式:名字 EQU 表达式 名字 = 表达式 操作:为表达式取一个名字,供以后引用 说明: 1、表达式可为常数、变量、标号、指令助记符、字符串 2、在一个源程序中,被EQU伪指令赋值的符号不能 再次赋值,而用=定义的符号名可重复定义. 3、赋值语句仅在汇编源程序时,作为替代符号用, 不产生目标代码,也不占有存储单元
赋值伪指令示例 CONST EQU 100*2 ;定义符号常数 ADDRS EQU [BX+10] ;为地址表达式定义名字 CHAR EQU ‘COMPUTER’ ;为字符串定义名字 COUNT = AX ;给寄存器定义名字 ... MOV BX, CONST ;引用 ADD BX, COUNT SUB ADDRS, 20 ... 等同于 MOV BX, 100*2 ADD BX, AX SUB [BX+10], 20
(六)地址计数器与对准伪指令 1)地址计数器$ ARRAY 01h 0074H 00 02h 0076H 00 7Ch 0078H 00 03h 007AH 00 04h 007CH 00 81h 007EH 00 示例1 ARRAY DW 1, 2, $+4, 3, 4, $+3 示例2 BUFFER DB 1, 2, 3, 4, 5 COUNT EQU $-BUFFER 数据定义的结果:COUNT的值即为BUFFER的长度 示例3 OUT 21H, AL JMP $+2 ; 跳转到下一句 MOV AX, 0
2)定位伪指令 格式1: ORG 表达式 格式2: ORG $+表达式 功能:将表达式的值送入程序计数器 $ 表示程序计数器的当前值 定位伪指令示例10H 20H D_SEG SEGMENT PARA 'DATA’ 11H 30H ORG 10H X DB 20H, 30H ORG $+5 17H 40H Y DB 40H, 50H 18H 50H D_SEG ENDS
3.3.5汇编语言源程序结构 • 完整段定义结构 • 简化段定义结构 • 程序段前缀结构