1、2019/6/11,1,32位汇编语言程序设计,计算机科学与信息工程学院 赵建州,2019/6/11,2,前 言,32位汇编语言程序设计是计算机软件课程。也是计算机专业学生的必修课程,与其他程序设计语言相比,汇编语言对机器的硬件层封装最少,在操作系统的控制下允许程序员最大限度地直接访问计算机硬件。汇编语言从语言的角度逼真地描述了微处理器的体系结构,从软件角度描述了计算机系统硬件层的运行规则。不同的CPU体系有不同的汇编语言。本课介绍的是Intel 80X86CPU系列的32位汇编语言。,2019/6/11,3,在学习计算机专业其他课程时,会遇到一些该课程不能解答的问题:常数为什么不能修改,数据
2、为什么要有数据类型,指针为什么也要有数据类型,为什么C/C+语言中数组的下标从0 开始,为什么不能用值传递参数或自动局部变量从函数带回信息,函数的形参变量和自动局部变量放在内存的哪一部分,它们为什么会随着函数的结束而消失, C/C+语言中为什么要区分整数运算和浮点数运算等等,通过学习32位汇编语言程序设计,会帮助你理解许多其他课程留下的问题。,2019/6/11,4,第一章 汇编语言单词第二章 CPU映像和机器数第三章 内存数据映像第四章 操作数寻址方式第五章 输入输出函数第六章 整型运算第七章 整型控制结构,结束放映,2019/6/11,5,第八章 浮点型运算第九章 指针和字符串第十章 数组
3、和串第十二章 过程,结束放映,2019/6/11,6,第一章 汇编语言单词,1.1 汇编语言字符集和单词 1.2 注释符 1.3 专用符号 1.4 保留字 1.5 标识符 1.6 汇编语言程序格式,2019/6/11,7,1.1 汇编语言字符集和单词,汇编语言采用ASCII码字符作为自己语言的字符集。 汇编语言的单词由一个或多个ASCII码字符组成,它们对于汇编程序有预定的语法意义。汇编语言的单词包括注释符、专用符号、保留字、标识符等。,2019/6/11,8,1.2 注释符,汇编语言的注释符分单行注释符和跨行注释符。单行释符 /可以放在程序某行中任何位置,编译程序忽略从 / 开始到行尾的所有
4、内容。跨行注释符 /* */编译程序忽略从 /* 开始到 */ 之间的所有内容。,2019/6/11,9,例1:注释的用法(1)跨行注释符/* 下面的程序段对数组实施快速排序算法 */ mov ( 365 , ecx); /* 给计数器赋初值 */(2)单行注释符mov ( 365 , ecx); / 给计数器赋初值,2019/6/11,10,1.3 专用符号,专用符号主要包括汇编语言的运算符、分隔符、数制标识符。专用符号有一个字符的也有两个字符的。下面是一个字符的专用符号。* / + - ( ) : ; , . = & | ! $ % “ 下面是两个字符的专用符号。& | = != = :=
5、 ,2019/6/11,11,例2:专用符号举例mov( ,2019/6/11,12,1.4 保留字,保留字也称关键字,保留字包括 CPU中的寄存器名,汇编语言的指令助记符,语句,数据类型名称等。汇编语言的保留字不区分大小写。,2019/6/11,13,CPU中的寄存器名 AL AH AX EAX BL BH BX EBX CL CH CX ECX DL DH DX EDX SI ESI DI EDI BP EBP SP ESP ST0 ST1 ST2 ST3 ST4 ST5 ST6 ST7,2019/6/11,14,指令助记符和语句 ADD INC ADC SUB DEC CMP NEG S
6、BB MUL IMUL INTMUL DIV IDIV MOD IMOD IF ELSE ENDIF WHILE ENDWHILE FOR ENDFOR FOREVER ENDFOR REPEAT UNTIL,2019/6/11,15,数据类型名称 int8 int16 int32 uns8 uns16 uns32 real32 real64 real80 byte word dword qword lword char string cset array boolean,2019/6/11,16,其他符号program begin end procedure typeval static v
7、ar readonly const 如果想了解汇编语言专用符号和保留字的更多的相关信息,请参考HLA手册。,2019/6/11,17,1.5 标识符,标识符可用作程序名、变量名、常量名、函数名、过程名、标号等。汇编语言的标识符必须以字母或下划线开始,后面可跟字母、数字、下划线。由于受MASM的限制,标识符的长度不能超过236个ASCII字符。汇编语言的标识符区分大小写字母。标识符不能与保留字同名。,2019/6/11,18,例3:合法的标识符和非法的标识符(1)合法的标识符addtion big first lasta1 s1 small Small(2)非法的标识符%a1 5s AL s1,
8、2019/6/11,19,1.6 汇编语言程序格式,program 程序名;begin 程序名; / 代码段end 程序名;,2019/6/11,20,程序中的program,begin,end 是汇编语言的保留字。程序名要按标识符取名。声明段用来声明各种变量、常量为它们赋予初值;还用来声明过程。begin和end之间是代码段。汇编语言提供了输入输出标准库,为了使用输入输出标准库,必须在程序开始用包含语句把标准库的头文件“stdlib.hhf“包含到程序中来。,2019/6/11,21,例3:显示“汇编语言编程开始了!” 的汇编语言程序 program HelloWorld; #include
9、( “stdlib.hhf“ ) / 包含标准库头文件 begin HelloWorld;stdout.put( “汇编语言编程开始了!“, nl );stdout.put( “击回车键退出 “ );stdin.readLn(); end HelloWorld;,2019/6/11,22,2019/6/11,23,2019/6/11,24,2019/6/11,25,如果用C+编写同样的程序,编写的代码如下: #include “stdafx.h“ #include “stdio.h“int main(int argc, char* argv) printf(“汇编语言编程开始了!n“);ret
10、urn 0; ,2019/6/11,26,#include “stdafx.h“ #include “iostream“ using namespace std; int main(int argc, char* argv) cout“汇编语言编程开始了!“endl;return 0; ,2019/6/11,27,汇编语言程序具有占用空间小,运行效率高 的优点,与这个汇编语言程序相似的C/C+ 程序经编译后产生的执行代码约有152KB, 而汇编语言编译的结果不到8K,汇编语言程 序常用于嵌入系统,控制系统编程,也用于 编写设备驱动程序,而设计图形界面不是汇 编语言的特长,每种程序语言都各有擅长
11、, 在应用中注意要扬长避短。,2019/6/11,28,第二章 机器数和CPU映像,2.1 整数机器数编码 2.2 机器整数的加减法运算及溢出问题 2.3 字符机器数编码 2.4 Intel 80x86 CPU映像,2019/6/11,29,2.1整数机器数编码,汇编语言语法把二进制整数分为两种,无符号和有符号整数。无符号整数是指数据的每一位都代表数值。在汇编语言程序设计里,内存地址(指针),循环次数,ASCII 码等都是无符号整数。数学运算中整数值有正数和负数之分,在计算机元件级怎样表示正号和负号?答案是只能用数字表示正号和负号。因此必须进行符号和数值混合编码。,2019/6/11,30,(
12、一)原码表示法 如果正数的符号用0 表示,负数的符号用1 表 示,绝对值用二进制数表示,这就是原码表 示法。假设计算机字长是n 位,能表示n-1位 有符号整数,设X=Xn-2Xn-3X0,原码表示是:0Xn-2Xn-3X0 X 0 X源码=1Xn-2Xn-3X0 X 0,2019/6/11,31,例1:设n=8,求二进制数10010, -10010的原 码。 二进制数 10010的原码是00010010,在此最 高位的0代表 + 号。 二进制数-10010的原码是10010010,在此最 高位的1代表 号。 根据定义, 0 在原码中有两种表示,所以计 算机内整数不采用原码表示法。,2019/6
13、/11,32,(二)补码表示法 n位二进制补码的定义是:X 0 X 2n-1-1 X补码=2n+X -2n-1 X 0 X是n-1位二进制整数,2019/6/11,33,二进制数转换为补码 二进制正数转换成补码与原码相同。 二进制负数转换成补码有两种方法: 方法1:根据定义求补码 例2:n=8,求( -1010111) 2和-119的补码。 -1010111补码 = 28-1010111=100000000-1010111=10101001-119补码 = 28-1110111=100000000-1110111=10001001,100000000101011110101001,100000
14、000111011110001001,2019/6/11,34,方法2:写出负数的绝对值,求绝对值的补码,然后对每位取反(包括符号位),末位加1。例3:n=8,求(- 1010111)2和-119的补码。计算(- 1010111)2 的补码 1 求负数绝对值 1010111 2 求补码 01010111 / n位补码 3 取反码 10101000 4 加1 10101001,2019/6/11,35,计算 - 119 的补码 1. 十进制换成二进制 - 1110111 2求负数绝对值 1110111 3求补码 01110111 4取反码 10001000 5末位加1 10001001,2019
15、/6/11,36,0在补码中只有一种表示法。整数数值在计算 机元件级用二进制补码表示。注意补码表示是 非对称性的。8位补码表示有符号数的范围是 -128127,16位补码表示有符号数的范围是 -3276832767 。 我们将补码逐位取反,再加1的运算称为求补 运算。正数的补码经过求补运算结果是它相反 数的补码;负数的补码经过求补运算结果也是 它相反数的补码。,2019/6/11,37,从机器数计算它的真值 对于正数,直接用权的多项式展开求和。 例:已知n=8位,求01001010的真值 用权的多项式展开求和: 原式=26+23+21=74 对于负数,有两种方法,每种方法有多个计算步骤。,20
16、19/6/11,38,方法一:根据补码的定义 X补码 = 2n+X - X = 2n - X补码 注意X本身是负数。 方法二:对负数的补码求补,得到它的绝对值,计算绝对值的权的多项式的和,然后对和实施取负运算。,2019/6/11,39,我们看同一个整数补码用不同位数表示时有何差别。 例4:求117,-117的8位和16位的补码。117 的补码 n = 8 01110101 n = 16 0000000001110101-117 的补码 n = 8 10001011 n = 16 1111111110001011 从例子中得出:一个8位补码数要变成16位补码数时 ,只需用它的符号位的值填满高8
17、位。这个操作称为 符号扩展。,2019/6/11,40,因为在计算机元件级无法区分一个二进制数是 有符号的还是无符号的。所以在机器内一个二 进制数可代表有符号数,也可代表无符号数。 例如: 假定n=8位,机器内有个整数 %10001010,它 可以代表无符号数138;也可以代表有符号数 -118。汇编语言程序员对程序中的整数哪些是 无符号的,哪些是有符号的必须一清二楚。,2019/6/11,41,2.2 机器整数加减法运算及溢出问题,(一)零扩展和符号扩展 计算机内整数的加法和减法运算要求参加运算数据 的长度要相同。如果参加运算的数据长度不同时, 在运算之前要把位数短的扩展为长的,否则运算结
18、果可能是错误的。对于无符号的数,高位部分全部 用0填满(零扩展);对于有符号的数,高位部分全部用 符号值填满(符号扩展)。加减运算时符号值与数值 一样参加运算。,2019/6/11,42,例5:计算两个无符号数加法 1010 + 01100000分析:无符号数位数不同时,位数短的必须进 行零扩展,即高4位必须填满0。1左加数零扩展 00001010 2加右加数 01100000 3运算结果 01101010,2019/6/11,43,例6:计算两个有符号数的加法 00001000 + 1100 即(8+(-4) 分析:有符号数位数不同时,必须进行符号扩展。因 为右加数最高位是1,代表负号,把它
19、变成8位时,高 4位必须填满符号值1。1左加数不变 00001000 2右加数符号扩展 11111100 3运算结果 100000100 因为数据位指定为8位,进位丢失,和等于00000100 即4,结果正确。,2019/6/11,44,如果不进行符号扩展,计算两个有符号数加法00001000+11001左加数不变 00001000 2右加数不符号扩展 1100 3运算的结果 00010100 结果等于20,显然是错误的。,2019/6/11,45,(二)整数加减运算可能出现的溢出问题 在计算机内运算与人类运算最大的不同之一 是计算机只能用有限位数表示数值。如果运 算结果超出了有限位数,称为溢
20、出。溢出是 一种错误,运算到此只能中断,要程序员修 改程序后,重新编译,再执行。,2019/6/11,46,无符号数加减运算和有符号数加减运算都有 可能发生溢出。 对于无符号数的加法,运算中最高位如产生 进位;对于无符号数减法,运算中最高位如 产生了借位,这都是溢出。,2019/6/11,47,例7:n=8,计算 130+1451130的机内表示 10000010 2145的机内表示 10001001 3运算的结果 100001011运算中最高位产生进位,由于机器内数据规定是8 位,进位丢失,这就是溢出,结果是错误的。,2019/6/11,48,例8:n=8,计算 130-1451130的机内
21、表示 10000010 2145的机内表示 10001001 3运算的结果 11111001运算中最高位产生借位,由于机器内数据规定是 8 位,借位丢失,这也是溢出,结果是错误的。,2019/6/11,49,根据补码定义和数学公理,有符号数加减法溢 出可能发生在两个同号数相加或两个异号数相 减的时候。如果两个同号数相加,结果的符号 与加数的符号相反;两个异号数相减,结果的 符号与减数的符号相同时,这就是溢出。因为 ,两个正数相加结果绝对不可能是负数;同样 一个负数减正数,结果绝对不可能是正数等等,2019/6/11,50,例9:n=8, 计算 72+98172的机内表示 01001000 29
22、8的机内表示 01100010 3运算的结果 10101010 结果不是正数,而是负数-86。显而易见结果 是错误的。,2019/6/11,51,例10:n=8, 计算 -83 +(-80)1-83的机内表示 10101101 2-80的机内表示 10110000 3运算结果 101011101 由于机器是8位,结果的最高位丢失,结果变 成正数93,是错误的。,2019/6/11,52,例11:n=8, 计算72-(-98)1 72的机内表示 01001000 2- 98的机内表示 10011110 3 运算的结果 10101010 结果与减数符号相同,正数减负数结果是负 数。它的值是-86。
23、结果是错误的。,2019/6/11,53,例12:n=8, 计算-83 801-83的机内表示 10101101 2 80的机内表示 01010000 3运算的结果 01011101 结果与减数符号相同,负数减正数结果是正 数。它的值是93。结果是错误的。,2019/6/11,54,2.3 字符型机器数编码,在计算机内,字符也必须用二进制数编码表示。最通用的字符是 ASCII 码字符,它是美国标准信息交换码。它用二进制代码规定了英文字母、阿拉伯数字、算术运算符、英文标点符号和其他常用符号以及控制符号的表示,ASCII 码包括了 128 个字符,具体内容见本书附录1。,2019/6/11,55,
24、中国在1980年发表GB2312-80信息交换码标准,这一标准后来被国际标准化组织接纳为国际标准,它是个双字节编码标准,一个汉字用两个字节表示,每个字节只用了低七位,每个字节的最高位值是0。因为ASCII码字符用一个字节的低七位表示,最高位的值也是0,而且它已经是机器数编码了,所以为了在机器里区分汉字和ASCII码,在机器里把汉字的GB2312码的每个字节的最高位的值规定为1后作为汉字的机器码。,2019/6/11,56,例13:输出汉字的机器码例如汉字“水”,它的机器码值是$AE_CB,要把机器码变成GB2312-80码,用机器码减$80_80即可,“水”字的GB2312码值是$2E_4B。
25、,2019/6/11,57,2.4 Intel 80x86映像,Intel 80x86 CPU 系列属于Von Neumann结构的机器,Von Neumann 计算机体系结构包括三个主要部分:中央处理单元(CPU),存储器,输入/输出设备(I/O)。这三部分由系统总线连在一起,见图2.1。系统总线包括控制总线、数据总线、地址总线。,2019/6/11,58,中央处理机CPU,总线控制逻辑,接 口,接 口,内 存,大容量 外存储器,I/O设备,I/O子系统,系统总线,. . .,. . .,图 2.1 计算机硬件结构,2019/6/11,59,从80486开始,Intel 把浮点运算协处理器集
26、成到CPU内,在CPU内称它为浮点运算单元(FPU),现暂不介绍浮点运算单元。CPU内部最显著的部件是寄存器。Intel CPU寄存器可分为四类:段寄存器,内核模式专用寄存器,通用寄存器,应用程序可访问的专用寄存器。,2019/6/11,60,段寄存器组包括CS、DS、SS、ES、FS、GS等6个16位寄存器。CS是代码段寄存器,SS是堆栈段寄存器,其余的是数据段寄存器。内核模式专用寄存器供系统编程使用,这里不做介绍。,2019/6/11,61,图2.2 80x86通用寄存器,2019/6/11,62,通用寄存器组包括EAX, EBX, ECX, EDX, ESI, EDI,EBP 和ESP
27、8个32位寄存器(图3.2)。每个名字开头 字母 “E” 代表扩展(extended)。这个前缀用来区 分8个32位寄存器和以下 8 个 16 位寄存器: AX, BX, CX, DX, SI, DI, BP和SP AX, BX, CX, DX 又可分成8 个8位寄存器: AL, AH, BL, BH, CL, CH, DL和DH Intel CPUs的这些寄存器不都是独立的寄存器, 当 修改一个寄存器时则至少同时修改了另一个寄存器。,2019/6/11,63,应用程序可访问的专用寄存器(1)标志寄存器Eflag 它是32 位寄存器。Bit 0 CF 最高位有进位或借位时置1 Bit 2 PF
28、 低8位有偶数个1时置1 Bit 4 AF D3位有进位或借位时置1 Bit 6 ZF 运算结果是零时置1,31 22 13 12 11 10 9 8 7 6 5 4 3 2 1 0,CF,PF,AF,ZF,SF,TF,IF,DF,OF,IOPL,保留,2019/6/11,64,Bit 7 SF 运算结果最高位是1时置1 Bit 8 TF 如置1每执行一条指令发生中断 Bit 9 IF 如置1允许响应可屏蔽中断 Bit 10 DF 请参考第十一章 Bit 11 OF 指令执行后发生溢出时置1,2019/6/11,65,很多指令执行后会影响条件标志,尤其在进行加减运算时,CPU并不知操作数是有符
29、号还是无符号数,它只是按照运算结果设置条件标志,需要程序员自己来判断运算结果是否正确。,2019/6/11,66,例14:计算 01001011+00111000左加数 01001011右加数 00111000相加结果 10000011运算结果使AF=1,OF=1,SF=1,ZF=0,CF=0, PF=0。如果这两个数是无符号数,运算结果是正确 的,因为没发生溢出(CF=0);如果这两个数是有 符号数,运算结果是错误的,因为发生了溢出(OF = 1)。这要由程序员自己判断。计算机硬件不保证运 算结果是否正确,只负责按结果设标志。,2019/6/11,67,(2)指令计数器EIP 指令计数器EI
30、P是32位寄存器,它存放着下一 条要执行的机器指令的偏移地址。程序装入 内存时,由操作系统负责把第一条指令的偏 移地址装入EIP,CPU每取一条指令就自动修 改EIP,将它的值变成下一条指令的偏移地址 。由于EIP起着直接保证程序正确执行的关键 作用,在80x86指令集中看不见EIP,2019/6/11,68,偏移地址是为了方便计算机内存系统管理而引入的一个逻辑地址概念,因为程序员在编程时,无法知道将来程序运行时放在内存的哪个位置,所以让编译程序在编译源程序时,以字节为单位按顺序给每条指令、每个数据赋予一个逻辑地址,并且每个段都从零开始编址,这个逻辑地址就称作偏移地址。在程序执行中,由内存管理
31、机构将逻辑地址映射到真正的物理地址。这部分内容将在寻址方式一章中介绍。,指令B,指令A,代码段,0,4,2019/6/11,69,(3)堆栈指针寄存器ESP32位寄存器ESP它只用来作为堆栈栈顶指针。它是 栈顶的偏移地址。堆栈操作指令都以它的值访问堆 栈。(4)堆栈指针、数据寄存器EBP32位EBP寄存器除了可用作数据寄存器外,还可用 作访问堆栈的指针寄存器,也是具有特殊用途的寄 存器。,2019/6/11,70, ,堆栈段,栈顶指针 ESP,基址指针EBP,0,16k,2019/6/11,71,第三章 内存数据映像,3.1 基本数据类型 3.2 常量 3.3 变量 3.4 程序分段,2019
32、/6/11,72,3.1 基本数据类型,汇编语言基本数据类型uns8 无符号的8位整数uns16 无符号的16位整数uns32 无符号的32位整数int8 有符号的8位整数int16 有符号的16位整数int32 有符号的32位整数boolean 布尔型,占一个字节char 字符类型,占一个字节,2019/6/11,73,real32 32位浮点数real64 64位浮点数real80 80位浮点数byte 通用的8位类型tbyte 通用的80位类型word 通用的16位类型dword 通用的32位类型qword 通用的64位类型lword 通用的128位类型,2019/6/11,74,汇编语
33、言复合数据类型string 字符串(字符串变量实际是4个字节长的指针)text 与字符串相似,文本常数常用于指令中,减小输入击键次数,2019/6/11,75,3.2 常量,3.2.1 数值常数和布尔型常数 3.2.2 字符串和字符常量 3.2.3 符号常量 3.2.4 常量表达式,2019/6/11,76,常量是编译程序时,已经有确定的值,在程 序运行中这个值不能改变。每个常量具有数 据类型,常量的类型可以用HLA的任何一种 类型。注意语法认为常量的数据类型是不明 确的。,2019/6/11,77,3.2.1 数值常数和布尔型常数,十进制整数进位计数制是常用的计数方法。人们习惯使用十进制,每
34、位的数字可以是0到9中的任何一个,它的基数是十,计数时逢十进一。这也是十进制的名称由来。,2019/6/11,78,在程序里可以用十进制整数。例1:123, 32_123, 0, -23高级汇编语言允许数值中用下划线作为分隔符,便于人们阅读。从语法上讲,数值前可有正号或负号,数值中允许有下划线,从语法上讲,下划线的位置可以在任意两个数字之间,在实际应用中将下划线作为千分号,使人们阅读方便。,2019/6/11,79,二进制整数 在数字电子计算机内,每位数字要用一个电子元件(如晶体管)的一个物理状态来表示,通常一个电子元件存在两种稳定的状态(如晶体管的饱和与截止),而一位二进制也存在两种状态0和
35、1。一个电子元件恰好可以表示一位二进制,所以在数字电子计算机内使用二进制。一个数值无论用二进制还是十进制表示,其本质是代表一个值。,2019/6/11,80,在程序里可以用二进制整数。高级汇编语言要求以 % 前缀开始,不能带符号。例2:%1101_0001高级汇编语言允许在数值中用下划线作为分隔符,便于人们阅读。,2019/6/11,81,n位m进制可以表示mn种状态。如三位二进制 可以表示23种状态:%000 %001 %010 %011 %100 %101 %110 %111,2019/6/11,82,十六进制整数用二进制表示数字对程序员来讲阅读和书写都不方便,为了方便阅读和书写程序,在汇
36、编语言源程序里还可以用十六进制表示数值。汇编语言要求以 $ 前缀开始,不能带符号。例3:$123, $12_1ae6高级汇编语言允许在数值中用下划线作为分隔符,便于人们阅读。,2019/6/11,83,在汇编语言源程序里程序员可以用上面三种数制中的任何一种表示自己的数据,其实机器只识别二进制,源程序中用非二进制表示的数由汇编程序或编译程序转换成二进制数。,2019/6/11,84,(4) 实型常数 HLA的浮点类型常数表示如下: (1)一个“+” 或 “-”表示尾数的符号。如没有符号,HLA默认它是正数。 (2)跟随一位或多位十进制数。(必选项) (3)跟随小数点和一位或多位十进制数(可选项)
37、。 (4)跟随一个“e”或“E”,其后是符号(“+”或“-“)和一位或多位十进制数。,2019/6/11,85,必须有小数点或”e”/“E”来区分浮点数和整数 注意浮点常量不能以小数点开始,在程序里 不能用“.1”表示“0.1” 。例4:合法的浮点常量1.234, 3.75e2, -1.0, 1.1e-1 , 0.1, -123.456e+789, +25e0, 1e+4, 1_234_837.25,1_000.00, 789_934.99 9_999.99,2019/6/11,86,布尔常数 HLA预定义两个布尔型常数,true 和false在内部,HLA定义true 和false值分别是1
38、和0。HLA默认为每个布尔型常量分配一个字节。实际上布尔操作只看布尔值的#0位而把其他位清零。你不能像在C/C+语言中在用布尔表达式的地方用整型表达式。,2019/6/11,87,3.2.2 字符串和字符常量,(1)字符串常量字符串常量是用双引号括住的零个或多个字符。 例5:“32位汇编语言“ “ “a“ “123“ 性质1:HLA自动将程序中相邻的字符串联接起来。 性质2:在字符串常量中插入两个双引号来代表一个双引号。,2019/6/11,88,(2)字符常量格式1:用两个单引号括住的一个ASCII码字符。 格式2:#整数常数。整数常数可以用十进制、十六进制或二进制,代表字符的ASCII码值
39、。数值在0到255的范围内,但只显示32到127范围内的字符。如果指定的数值超过0到255的范围,系统在编译时会报错。系统默认为每个字符常量分配一个字节。,2019/6/11,89,性质1:在两个单引号中放两个单引号代表一 个单引号。 性质2:HLA可以联接任何相邻的字符常量和 字符串常量组成一个字符串常量 在程序中,语法认为字符常量的数据类型是 不明确的。,2019/6/11,90,例7: 2 ,a ,#13,#$d,#%1101 上面第三个字符表示一个单引号,后面的三个 字符都代表回车 。记住在程序中“a” 和 a是不 相同的。,2019/6/11,91,3.2.3 符号常量,在HLA的C
40、ONST段声明符号常量。该段中 声明的常量的值从编译到运行都不会改变; 该段位于程序中的声明段位置。它以CONST 保留字开始。CONST标识符 :数据类型 := 常数表达式;标识符 := 常数表达式; 第二种格式是省略数据类型的语法格式,此时系统自动赋予默认数据类型。HLA按数据类型为符号常量分配内存空间。,2019/6/11,92,在CONST段声明常量时,必须对其初始化。 := 在语法里是赋值号且只能用于数据定义的场合。在程序运行中,不允许对CONST段中的对象进行修改。在CONST段中声明字符串常量可以省略数据类型,但文本常量不能省略数据类型。虽然,声明符号常量时,设置了数据类型,这里
41、数据类型仅仅是为给常量分配内存单元而设置的,在指令中,语法仍然认为符号常量的数据类型是不明确的,2019/6/11,93,例9:带数据类型的常量声明。 const pi: real32 := 3.14159; Max:uns32 := 15; des:char := /; Mask:byte := $F0; Active: Boolean := true; 例10:不带数据类型的常量声明。 const pi:= 3.14159; / 默认类型是 real80Max:= 15; / 默认类型是uns32 Des:= /; / 默认类型是char Active:= true; / 默认类型是boo
42、lean,2019/6/11,94,3.2.4 常量表达式,常数表达式的形式与高级语言的相似,他们包括字符、数字常量和前面已声明过的符号常量,各种运算符。常量表达式在语法上仍是常量。,2019/6/11,95,- (一元运算符) 对“-”后的表达式取负* 乘法div 整数除法 整数除以整数,取商的整数mod 求余 整数除以整数,取余数/ 除法 结果是浮点数+ 加法- 减法,2019/6/11,96,例13:对于常数表达式,汇编语言在编译程序时计算出值。 const x := 10; y := 6; Sum := x + y; / 常量表达式 HLA在编译时直接翻译常量表达式的值。它不 为计算常
43、量表达式“x+y”编译出机器指令,它 直接计算这两个常数值的和。从此,在本程序 里汇编语言把16和常数Sum联系起来。,2019/6/11,97,3.3 变量,3.3.1 有符号整型变量 3.3.2 无符号整型变量 3.3.3 实型变量 3.3.4 布尔型变量 3.3.5 字符型变量,2019/6/11,98,变量要先定义,后使用。程序员要按照变量的性质, 在相应的段中定义变量。定义变量的语法: 变量名:数据类型;变量名:数据类型 := 常量表达式;变量名按标识符取名。数据类型可以是HLA的任何一种数据类型。:= 在语法里是赋值号且只能用于数据定义的场合。常量的类型必须与指定的数据类型一致。,
44、2019/6/11,99,3.3.1 有符号整型变量,汇编语言常用的三种长度的有符号的十进制整数类型分别是:int8, int16,int32。分别对应长度为一个字节、两个字节和四个字节的有符号整数。HLA 按照数据类型为每个有符号整数变量分配内存空间。例15:i8:int8;i16:int16;i32:int32;,2019/6/11,100,在声明变量时,可以赋给变量一个初始值,在 程序装入内存时由操作系统赋予变量。例16:i8:int8 :=8;i16:int16 :=1600;i32:int32 :=-320000;在赋值号(“:=”)后边必须是常数表达式。不能用另一个变量给变量赋值。
45、,2019/6/11,101,3.3.2 无符号整型变量,HLA常用的三种长度的无符号十进制整数类型分别是:uns8,uns16,uns32。分别对应一个字节、两个字节和四个字节的无符号整数。HLA按照数据类型为每个无符号整数变量分配内存空间。例17:声明无符号整数变量u8: uns8; u16: uns16; u32: uns32;,2019/6/11,102,例18:声明变量时赋初值u8: uns8:=255; u16: uns16:=6500; u32: uns32:=5900;,2019/6/11,103,3.3.3 实型变量,HLA只有三种长度的浮点类型:real32 (4个字节)
46、代表单精度浮点数,real64(8个字节) 代表双精度浮点数,real80(10个字节)代表扩展精度浮点数。汇编语言根据数据类型为每个浮点型变量分配内存空间。系统把浮点类型数值一律当做有符号的数值。,2019/6/11,104,例19:定义浮点型变量f32a1: real32; f32a2: real32 := 2.7; pi: real32 := 3.14159; f64b1: real64; f64b2: real64 := 1.23456789e+10; f80c1: real80; f80c2: real80 := -1.0e-104;,2019/6/11,105,3.3.4 布尔型变
47、量,HLA汇编语言程序中可以使用布尔型常量和变量,用 布尔型变量或常量组成布尔型表达式,一个布尔型变 量是最简单的布尔型表达式。例20:a: boolean; b: boolean := false; c: boolean := true; 每个布尔型变量占一个字节。你能声明未初始化的变 量也能声明初始化的变量。,2019/6/11,106,3.3.5 字符型变量,你能用char 数据类型声明占一个字节的ASCII 字符变量。例21:字符变量的定义c: char; d: char := A;,2019/6/11,107,3.4 程序分段,3.4.1 代码段 3.4.2 静态数据段 3.4.4 堆栈段 3.4.5 自动变量段 3.4.6 类型段(略) 3.4.7 符号常量段(略) 3.4.8 在程序中声明段的组织形式(略) 3.4.9 数据在内存中存放格式,2019/6/11,108,3.4.1代码段,汇编语言程序从begin 开始到end 之间的所有指令和数据组成代码段,代码段是一个程序的执行规则,它用指令描述了程序的功能,在代码段里放的是指令及指令中携带的数据根据计算机工作原理,CPU从内存取来第一条指令,执行,然后取下一条指令,再执行直到执行完最后一条指令,程序结束。为了实现程序运行,CPU必须知道指令在哪里,为了帮助CPU找到指令,人们做出了这样设,