1、2022-7-3012022-7-302前 言32位汇编语言程序设计是计算机软件课程。也是计算机专业学生的必修课程,与其他程序设计语言相比,汇编语言对机器的硬件层封装最少,在操作系统的控制下允许程序员最大限度地直接访问计算机硬件。汇编语言从语言的角度逼真地描述了微处理器的体系结构,从软件角度描述了计算机系统硬件层的运行规则。不同的CPU体系有不同的汇编语言。本课介绍的是Intel 80X86CPU系列的32位汇编语言。2022-7-303在学习计算机专业其他课程时,会遇到一些该课程不能解答的问题:常数为什么不能修改,数据为什么要有数据类型,指针为什么也要有数据类型,为什么C/C+语言中数组的下
2、标从0 开始,为什么不能用值传递参数或自动局部变量从函数带回信息,函数的形参变量和自动局部变量放在内存的哪一部分,它们为什么会随着函数的结束而消失,C/C+语言中为什么要区分整数运算和浮点数运算等等,通过学习32位汇编语言程序设计,会帮助你理解许多其他课程留下的问题。2022-7-304 第一章第一章 汇编语言单词汇编语言单词 第二章第二章 CPU映像和机器数映像和机器数 第三章第三章 内存数据映像内存数据映像 第四章第四章 操作数寻址方式操作数寻址方式第五章第五章 输入输出函数输入输出函数 第六章第六章 整型运算整型运算 第七章第七章 整型控制结构整型控制结构结束放映结束放映2022-7-3
3、05 第八章第八章 浮点型运算浮点型运算 第九章第九章 指针和字符串指针和字符串 第十章第十章 数组和串数组和串第十二章第十二章 过程过程 结束放映结束放映2022-7-306第一章 汇编语言单词1.1 汇编语言字符集和单词1.2 注释符1.3 专用符号1.4 保留字1.5 标识符1.6 汇编语言程序格式2022-7-3071.1 汇编语言字符集和单词汇编语言采用ASCII码字符作为自己语言的字符集。汇编语言的单词由一个或多个ASCII码字符组成,它们对于汇编程序有预定的语法意义。汇编语言的单词包括注释符、专用符号、保留字、标注释符、专用符号、保留字、标识符等。识符等。2022-7-3081.
4、2 注释符 汇编语言的注释符分单行注释符和跨行注释符。单行释符/可以放在程序某行中任何位置,编译程序忽略从/开始到行尾的所有内容。跨行注释符/*/编译程序忽略从/*开始到*/之间的所有内容。2022-7-309例1:注释的用法 (1)跨行注释符)跨行注释符 /*下面的程序段对数组下面的程序段对数组 实施快速排序算法实施快速排序算法 */mov(365,ecx);/*给计数器赋初值给计数器赋初值*/(2)单行注释符)单行注释符 mov(365,ecx);/给计数器赋初值给计数器赋初值2022-7-30101.3 专用符号专用符号主要包括汇编语言的运算符、分专用符号主要包括汇编语言的运算符、分隔符
5、、数制标识符。专用符号有一个字符隔符、数制标识符。专用符号有一个字符的也有两个字符的。下面是一个字符的专的也有两个字符的。下面是一个字符的专用符号。用符号。*/+-():;,./+-():;,.=&|!$%=&|!$%下面是两个字符的专用符号。下面是两个字符的专用符号。&|=!=:=.&|=!=:=.2022-7-3011例2:专用符号举例 mov(&data,eax);stdout.put(32位汇编语言,nl);stdout.put(pi=,pi:10:3,nl);stdout.put($6f,nl);stdout.put(%10101010,nl);2022-7-30121.4 保留字
6、保留字也称关键字,保留字包括 CPU中的寄存器名,汇编语言的指令助记符,语句,数据类型名称等。汇编语言的保留字不区分大小写。2022-7-3013 CPU中的寄存器名AL AH AX EAX BL BH BX EBX CL CH CX ECX DL DH DX EDX SI ESIDI EDIBP EBPSP ESPST0 ST1 ST2 ST3 ST4 ST5 ST6 ST72022-7-3014 指令助记符和语句ADD INC ADCSUB DEC CMP NEG SBBMUL IMUL INTMUL DIV IDIV MOD IMODIF ELSE ENDIFWHILE ENDWHILE
7、 FOR ENDFORFOREVER ENDFOR REPEAT UNTIL 2022-7-3015 数据类型名称int8 int16 int32uns8 uns16 uns32real32 real64 real80byte word dword qword lword char string cset array boolean2022-7-3016 其他符号其他符号 program begin end procedure type val static var readonly const 如果想了解汇编语言专用符号和保留字的更多的相关信息,请参考HLA手册。2022-7-30171.5
8、 标识符标识符可用作程序名、变量名、常量名、函数名、过程名、标号等。汇编语言的标识符汇编语言的标识符必须以字母或下划线开始,后面可跟字母、必须以字母或下划线开始,后面可跟字母、数字、下划线数字、下划线。由于受MASM的限制,标识符的长度不能超过236个ASCII字符。汇编语言汇编语言的标识符区分大小写字母的标识符区分大小写字母。标识符不能与保留字同名。2022-7-3018 例3:合法的标识符和非法的标识符(1)合法的标识符 addtion big first last a1 s1 small Small(2)非法的标识符%a1 5s AL s12022-7-30191.6 汇编语言程序格式
9、program 程序名程序名;begin 程序名程序名;/代码段 end 程序名程序名;2022-7-3020 程序中的program,begin,end 是汇编语言的保留字。程序名要按标识符取名。声明段用来声明各种变量、常量为它们赋予初值;还用来声明过程。begin和end之间是代码段。汇编语言提供了输入输出标准库,为了使用输入输出标准库,必须在程序开始用包含语句把标准库的头文件stdlib.hhf包含到程序中来。2022-7-3021例3:显示“汇编语言编程开始了!”的汇编语言程序program HelloWorld;#include(stdlib.hhf)/包含标准库头文件begin H
10、elloWorld;stdout.put(汇编语言编程开始了!,nl);stdout.put(“击回车键退出 );stdin.readLn();end HelloWorld;2022-7-30222022-7-30232022-7-30242022-7-3025如果用C+编写同样的程序,编写的代码如下:#include stdafx.h#include stdio.hint main(int argc,char*argv)printf(汇编语言编程开始了!n);return 0;2022-7-3026#include stdafx.h#include iostreamusing namespa
11、ce std;int main(int argc,char*argv)cout汇编语言编程开始了!endl;return 0;2022-7-3027汇编语言程序具有占用空间小,运行效率高的优点,与这个汇编语言程序相似的C/C+程序经编译后产生的执行代码约有152KB,而汇编语言编译的结果不到8K,汇编语言程序常用于嵌入系统,控制系统编程,也用于编写设备驱动程序,而设计图形界面不是汇编语言的特长,每种程序语言都各有擅长,在应用中注意要扬长避短。2022-7-3028第二章 机器数和CPU映像2.1 整数机器数编码2.2 机器整数的加减法运算及溢出问题2.3 字符机器数编码2.4 Intel 80
12、 x86 CPU映像2022-7-30292.1整数机器数编码 汇编语言语法语法把二进制整数分为两种,无符号和有符号整数。无符号整数是指数据的每一位都代表数值。在汇编语言程序设计里,内存地址(指针),循环次数,ASCII 码等都是无符号整数。数学运算中整数值有正数和数学运算中整数值有正数和负数之分,在计算机元件级怎样表示正号和负数之分,在计算机元件级怎样表示正号和负号?答案是只能用数字表示正号和负号。负号?答案是只能用数字表示正号和负号。因此必须进行符号和数值混合编码。因此必须进行符号和数值混合编码。2022-7-3030 (一)原码表示法 如果正数的符号用0 表示,负数的符号用1 表示,绝对
13、值用二进制数表示,这就是原码表示法。假设计算机字长是n 位,能表示n-1位有符号整数,设X=Xn-2Xn-3X0,原码表示是:0Xn-2Xn-3X0 X 0X源码=1Xn-2Xn-3X0 X 02022-7-3031例1:设n=8,求二进制数10010,-10010的原码。二进制数 10010的原码是00010010,在此最高位的0代表+号。二进制数-10010的原码是10010010,在此最高位的1代表 号。根据定义,根据定义,0 在原码中有两种表示,所以计在原码中有两种表示,所以计算机内整数不采用原码表示法。算机内整数不采用原码表示法。2022-7-3032 (二)补码表示法 n位二进制补
14、码的定义是:X 0 X2n-1-1X补码=2n+X -2n-1X0X是是n-1位二进制整数位二进制整数2022-7-3033二进制数转换为补码二进制正数正数转换成补码与原码相同。二进制负数负数转换成补码有两种方法:方法1:根据定义求补码例2:n=8,求(-1010111)2和-119的补码。-1010111补码=28-1010111 =100000000-1010111 =10101001 -119补码=28-1110111 =100000000-1110111 =10001001 100000000-1010111 10101001 100000000-1110111 10001001202
15、2-7-3034 方法2:写出负数的绝对值,求绝对值的补码,然后对每位取反(包括符号位),末位加1。例3:n=8,求(-1010111)2和-119的补码。计算(-1010111)2 的补码1 求负数绝对值 10101112 求补码 01010111 /n位补码位补码 3 取反码 101010004 加1 101010012022-7-3035 计算 -119 的补码1.十进制换成二进制 -11101112求负数绝对值 11101113求补码 011101114取反码 100010005末位加1 100010012022-7-30360在补码中只有一种表示法。整数数值在计算机元件级用二进制补码
16、表示。注意补码表示是非对称性的。8位补码表示有符号数的范围是-128127,16位补码表示有符号数的范围是-3276832767。我们将补码逐位取反,再加1的运算称为求补运算。正数的补码经过求补运算结果是它相反正数的补码经过求补运算结果是它相反数的补码;负数的补码经过求补运算结果也是数的补码;负数的补码经过求补运算结果也是它相反数的补码。它相反数的补码。2022-7-3037从机器数计算它的真值对于正数,直接用权的多项式展开求和。例:已知n=8位,求01001010的真值用权的多项式展开求和:原式=26+23+21=74对于负数,有两种方法,每种方法有多个计算步骤。2022-7-3038方法一
17、:根据补码的定义X补码=2n+X-X=2n-X补码 注意X本身是负数。方法二:对负数的补码求补,得到它的绝对值,计算绝对值的权的多项式的和,然后对和实施取负运算。2022-7-3039我们看同一个整数补码用不同位数表示时有何差别。例4:求117,-117的8位和16位的补码。117 的补码n=8 01110101n=16 0000000001110101 -117 的补码n=8 10001011n=16 1111111110001011从例子中得出:一个8位补码数要变成16位补码数时,只需用它的符号位的值填满高8位。这个操作称为符号扩展符号扩展。2022-7-3040因为在计算机元件级无法区分
18、一个二进制数是有符号的还是无符号的。所以在机器内一个二进制数可代表有符号数,也可代表无符号数。例如:假定n=8位,机器内有个整数%10001010,它可以代表无符号数138;也可以代表有符号数-118。汇编语言程序员对程序中的整数哪些是无符号的,哪些是有符号的必须一清二楚。2022-7-30412.2 机器整数加减法运算及溢出问题(一)零扩展和符号扩展计算机内整数的加法和减法运算要求参加运算数据的长度要相同。如果参加运算的数据长度不同时,在运算之前要把位数短的扩展为长的,否则运算结果可能是错误的。对于无符号的数,高位部分全部用0填满(零扩展零扩展);对于有符号的数,高位部分全部用符号值填满(符
19、号扩展符号扩展)。加减运算时符号值与数值加减运算时符号值与数值一样参加运算。一样参加运算。2022-7-3042例5:计算两个无符号数加法 1010+01100000分析:无符号数位数不同时,位数短的必须进行零扩展,即高4位必须填满0。1左加数零扩展 000010102加右加数 011000003运算结果 011010102022-7-3043例6:计算两个有符号数的加法 00001000+1100 即(8+(-4)分析:有符号数位数不同时,必须进行符号扩展。因为右加数最高位是1,代表负号,把它变成8位时,高4位必须填满符号值1。1左加数不变 000010002右加数符号扩展 11111100
20、3运算结果 100000100因为数据位指定为8位,进位丢失,和等于00000100即4,结果正确。2022-7-3044如果不进行符号扩展,计算两个有符号数加法 00001000+11001左加数不变 000010002右加数不符号扩展 11003运算的结果 00010100结果等于20,显然是错误的。2022-7-3045(二)整数加减运算可能出现的溢出问题在计算机内运算与人类运算最大的不同之一是计算机只能用有限位数表示数值。如果运算结果超出了有限位数,称为溢出。溢出是一种错误,运算到此只能中断,要程序员修改程序后,重新编译,再执行。2022-7-3046无符号数加减运算和有符号数加减运算
21、都有可能发生溢出。对于无符号数的加法,运算中最高位如产生进位;对于无符号数减法,运算中最高位如产生了借位,这都是溢出。2022-7-3047例7:n=8,计算 130+145 1130的机内表示 100000102145的机内表示 100010013运算的结果 100001011 运算中最高位产生进位,由于机器内数据规定是8 位,进位丢失,这就是溢出,结果是错误的。2022-7-3048例8:n=8,计算 130-145 1130的机内表示 100000102145的机内表示 100010013运算的结果 11111001 运算中最高位产生借位,由于机器内数据规定是 8 位,借位丢失,这也是溢
22、出,结果是错误的。2022-7-3049根据补码定义和数学公理,有符号数加减法溢出可能发生在两个同号数相加或两个异号数相减的时候。如果两个同号数相加,结果的符号与加数的符号相反;两个异号数相减,结果的符号与减数的符号相同时,这就是溢出。因为,两个正数相加结果绝对不可能是负数;同样一个负数减正数,结果绝对不可能是正数等等2022-7-3050例9:n=8,计算 72+98 172的机内表示 01001000298的机内表示 011000103运算的结果 10101010结果不是正数,而是负数-86。显而易见结果是错误的。2022-7-3051例10:n=8,计算-83+(-80)1-83的机内表
23、示 101011012-80的机内表示 101100003运算结果 101011101由于机器是8位,结果的最高位丢失,结果变成正数93,是错误的。2022-7-3052例11:n=8,计算72-(-98)1 72的机内表示 010010002-98的机内表示 100111103 运算的结果 10101010结果与减数符号相同,正数减负数结果是负数。它的值是-86。结果是错误的。2022-7-3053例12:n=8,计算-83 80 1-83的机内表示 101011012 80的机内表示 010100003运算的结果 01011101结果与减数符号相同,负数减正数结果是正数。它的值是93。结果
24、是错误的。2022-7-30542.3 字符型机器数编码在计算机内,字符也必须用二进制数编码表示。最通用的字符是 ASCII 码字符,它是美国标准信息交换码。它用二进制代码规定了英文字母、阿拉伯数字、算术运算符、英文标点符号和其他常用符号以及控制符号的表示,ASCII 码包括了 128 个字符,具体内容见本书附录1。2022-7-3055中国在1980年发表GB2312-80信息交换码标准,这一标准后来被国际标准化组织接纳为国际标准,它是个双字节编码标准,一个汉字用两个字节表示,每个字节只用了低七位,每个字节的最高位值是0。因为ASCII码字符用一个字节的低七位表示,最高位的值也是0,而且它已
25、经是机器数编码了,所以为了在机器里区分汉字和ASCII码,在机器里把汉字的GB2312码的每个字节的最高位的值规定为1后作为汉字的机器码。2022-7-3056例13:输出汉字的机器码例如汉字“水”,它的机器码值是$AE_CB,要把机器码变成GB2312-80码,用机器码减$80_80即可,“水”字的GB2312码值是$2E_4B。2022-7-30572.4 Intel 80 x86映像Intel 80 x86 CPU 系列属于Von Neumann结构的机器,Von Neumann 计算机体系结构包括三个主要部分:中央处理单元(CPU),存储器,输入/输出设备(I/O)。这三部分由系统总线
26、连在一起,见图2.1。系统总线包括控制总线、数据总线、地址总线。2022-7-3058中央处理机中央处理机 CPU总线控制 逻辑接接 口口接接 口口内内 存存 大容量大容量外存储器外存储器I/O设备设备I/O子系统子系统系统总线系统总线.图 2.1 计算机硬件结构 2022-7-3059从80486开始,Intel 把浮点运算协处理器集成到CPU内,在CPU内称它为浮点运算单元(FPU),现暂不介绍浮点运算单元。CPU内部最显著的部件是寄存器。Intel CPU寄存器可分为四类:段寄存器,内核模式专用寄存器,通用寄存器,应用程序可访问的专用寄存器。2022-7-3060 段寄存器组包括CS、D
27、S、SS、ES、FS、GS等6个16位寄存器。CS是代码段寄存器,SS是堆栈段寄存器,其余的是数据段寄存器。内核模式专用寄存器供系统编程使用,这里不做介绍。2022-7-3061 图2.2 80 x86通用寄存器2022-7-3062通用寄存器组包括EAX,EBX,ECX,EDX,ESI,EDI,EBP 和ESP 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,D
28、L和和DH Intel CPUs的这些寄存器不都是独立的寄存器,当修改一个寄存器时则至少同时修改了另一个寄存器。2022-7-3063 应用程序可访问的专用寄存器(1)标志寄存器Eflag 它是32 位寄存器。Bit 0 CF 最高位有进位或借位时置1Bit 2 PF 低8位有偶数个1时置1Bit 4 AF D3位有进位或借位时置1Bit 6 ZF 运算结果是零时置1 31 .22 13 12 11 10 9 8 7 6 5 4 3 2 1 0CFPFAFZFSFTFIFDFOFIOPL保留保留2022-7-3064Bit 7 SF 运算结果最高位是1时置1Bit 8 TF 如置1每执行一条指
29、令发生中断Bit 9 IF 如置1允许响应可屏蔽中断Bit 10 DF 请参考第十一章Bit 11 OF 指令执行后发生溢出时置12022-7-3065 很多指令执行后会影响条件标志,尤其在进行加减运算时,CPU并不知操作数是有符号还是无符号数,它只是按照运算结果设置条件标志,需要程序员自己来判断运算结果是否正确。2022-7-3066例14:计算 01001011+00111000 左加数 01001011 右加数 00111000 相加结果 10000011运算结果使AF=1,OF=1,SF=1,ZF=0,CF=0,PF=0。如果这两个数是无符号数,运算结果是正确的,因为没发生溢出(CF=
30、0);如果这两个数是有符号数,运算结果是错误的,因为发生了溢出(OF=1)。这要由程序员自己判断。计算机硬件不保证运计算机硬件不保证运算结果是否正确,只负责按结果设标志算结果是否正确,只负责按结果设标志。2022-7-3067(2)指令计数器EIP指令计数器EIP是32位寄存器,它存放着下一条要执行的机器指令的偏移地址偏移地址。程序装入内存时,由操作系统负责把第一条指令的偏移地址装入EIP,CPU每取一条指令就自动修改EIP,将它的值变成下一条指令的偏移地址。由于EIP起着直接保证程序正确执行的关键作用,在80 x86指令集中看不见EIP2022-7-3068偏移地址是为了方便计算机内存系统管
31、理而引入的一个逻辑地址概念,因为程序员在编程时,无法知道将来程序运行时放在内存的哪个位置,所以让编译程序在编译源程序时,以字节为单位按顺序给每条指令、每个数据赋予一个逻辑地址,并且每个段都从零开始编址,这个逻辑地址就称作偏移地址。在程序执行中,由内存管理机构将逻辑地址映射到真正的物理地址。这部分内容将在寻址方式一章中介绍。指令指令B指令指令A代码段代码段0 04 42022-7-3069(3)堆栈指针寄存器ESP32位寄存器ESP它只用来作为堆栈栈顶指针。它是栈顶的偏移地址。堆栈操作指令都以它的值访问堆栈。(4)堆栈指针、数据寄存器EBP32位EBP寄存器除了可用作数据寄存器外,还可用作访问堆
32、栈的指针寄存器,也是具有特殊用途的寄存器。2022-7-3070 堆栈段堆栈段栈顶指针栈顶指针 ESP基址指针基址指针EBP016k2022-7-3071第三章 内存数据映像3.1 基本数据类型3.2 常量3.3 变量3.4 程序分段2022-7-30723.1 基本数据类型 汇编语言基本数据类型汇编语言基本数据类型uns8 无符号的8位整数uns16 无符号的16位整数uns32 无符号的32位整数int8 有符号的8位整数int16 有符号的16位整数int32 有符号的32位整数boolean 布尔型,占一个字节char 字符类型,占一个字节2022-7-3073real32 32位浮点
33、数real64 64位浮点数real80 80位浮点数byte 通用的8位类型tbyte 通用的80位类型word 通用的16位类型dword 通用的32位类型qword 通用的64位类型lword 通用的128位类型2022-7-3074 汇编语言复合数据类型 string 字符串(字符串变量实际是4个字节长的指针)text 与字符串相似,文本常数常用于指令中,减小输入击键次数2022-7-30753.2 常量3.2.1 数值常数和布尔型常数3.2.2 字符串和字符常量3.2.3 符号常量3.2.4 常量表达式2022-7-3076常量是编译程序时,已经有确定的值,在程序运行中这个值不能改变
34、。每个常量具有数据类型,常量的类型可以用HLA的任何一种类型。注意语法认为常量的数据类型是不明注意语法认为常量的数据类型是不明确的。确的。2022-7-30773.2.1 数值常数和布尔型常数(1)十进制整数进位计数制是常用的计数方法。人们习惯使用十进制,每位的数字可以是0到9中的任何一个,它的基数是十,计数时逢十进一。这也是十进制的名称由来。2022-7-3078在程序里可以用十进制整数。例1:123,32_123,0,-23高级汇编语言允许数值中用下划线作为分隔符,便于人们阅读。从语法上讲,数值前可有正号或负号,数值中允许有下划线,从语法上讲,下划线的位置可以在任意两个数字之间,在实际应用
35、中将下划线作为千分号,使人们阅读方便。2022-7-3079(2)二进制整数 在数字电子计算机内,每位数字要在数字电子计算机内,每位数字要用一个用一个电子元件(如晶体管)的一个物理状态来电子元件(如晶体管)的一个物理状态来表示表示,通常一个电子元件存在两种稳定的,通常一个电子元件存在两种稳定的状态(如晶体管的饱和与截止),而一位状态(如晶体管的饱和与截止),而一位二进制也存在两种状态二进制也存在两种状态0和和1。一个电子元。一个电子元件恰好可以表示一位二进制,所以在数字件恰好可以表示一位二进制,所以在数字电子计算机内使用二进制。一个数值无论电子计算机内使用二进制。一个数值无论用二进制还是十进制
36、表示,其本质是代表用二进制还是十进制表示,其本质是代表一个值。一个值。2022-7-3080在程序里可以用二进制整数。高级汇编语言要求以%前缀开始,不能带符号。例2:%1101_0001高级汇编语言允许在数值中用下划线作为分隔符,便于人们阅读。2022-7-3081n位m进制可以表示mn种状态。如三位二进制可以表示23种状态:%000%001%010%011%100%101%110%1112022-7-3082十六进制整数十六进制整数用二进制表示数字对程序员来讲阅读和书写都不方便,为了方便阅读和书写程序,在汇编语言源程序里还可以用十六进制表示数值。汇编语言要求以$前缀开始,不能带符号。例3:$
37、123,$12_1ae6高级汇编语言允许在数值中用下划线作为分隔符,便于人们阅读。2022-7-3083在汇编语言源程序里程序员可以用上面三种数制中的任何一种表示自己的数据,其实机器只识别二进制,源程序中用非二进制表示的数由汇编程序或编译程序转换成二进制数。2022-7-3084(4)实型常数 HLA的浮点类型常数表示如下:(1)一个“+”或“-”表示尾数的符号。如没有 符号,HLA默认它是正数。(2)跟随一位或多位十进制数。(必选项)(3)跟随小数点和一位或多位十进制数(可 选项)。(4)跟随一个“e”或“E”,其后是符号(“+”或 -)和一位或多位十进制数。2022-7-3085必须有小数
38、点或”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 2022-7-3086(5)布尔常数 HLA预定义两个布尔型常数,true 和false在内部,HLA定义true 和false值分别是1和0。HLA默认为每个布尔型常量分配一个字节。实际上布尔操作只看布尔值的#0位而把其他位清零。你不能像在C/C+语言中在用布尔表达式的地方用整型
39、表达式。2022-7-30873.2.2 字符串和字符常量 (1)字符串常量 字符串常量是用双引号括住的零个或多个字符。例5:32位汇编语言 a 123性质1:HLA自动将程序中相邻的字符串联接起来。性质2:在字符串常量中插入两个双引号来代表一个 双引号。2022-7-3088(2)字符常量格式1:用两个单引号括住的一个ASCII码字 符。格式2:#整数常数。整数常数可以用十进制、十六进制或二进制,代表字符的ASCII码值。数值在0到255的范围内,但只显示32到127范围内的字符。如果指定的数值超过0到255的范围,系统在编译时会报错。系统默认为每个字符常量分配一个字节。2022-7-308
40、9性质1:在两个单引号中放两个单引号代表一个单引号。性质2:HLA可以联接任何相邻的字符常量和字符串常量组成一个字符串常量在程序中,语法认为字符常量的数据类型是在程序中,语法认为字符常量的数据类型是不明确的。不明确的。2022-7-3090例7:2,a,#13,#$d,#%1101上面第三个字符表示一个单引号,后面的三个字符都代表回车。记住在程序中“a”和 a是不相同的。2022-7-30913.2.3 符号常量 在HLA的CONST段声明符号常量。该段中声明的常量的值从编译到运行都不会改变;该段位于程序中的声明段位置。它以CONST保留字开始。CONST 标识符:数据类型:=常数表达式;标识
41、符:=常数表达式;第二种格式是省略数据类型的语法格式,此时系统自动赋予默认数据类型。HLA按数据类型为符号常量分配内存空间。2022-7-3092 在CONST段声明常量时,必须对其初始化。:=在语法里是赋值号且只能用于在语法里是赋值号且只能用于数据数据定义定义的场合。的场合。在程序运行中,不允许对CONST段中的对象进行修改。在CONST段中声明字符串常量可以省略数据类型,但文本常量不能省略数据类型。虽然,声明符号常量时,设置了数据类型,这里数据类型仅仅是为给常量分配内存单元而设置的,在指令中,语法仍在指令中,语法仍然认为符号常量的数据类型是不明确的然认为符号常量的数据类型是不明确的2022
42、-7-3093例9:带数据类型的常量声明。const pi:real32:=3.14159;Max:uns32 :=15;des:char :=/;Mask:byte:=$F0;Active:Boolean:=true;例10:不带数据类型的常量声明。const pi:=3.14159;/默认类型是 real80 Max:=15;/默认类型是uns32 Des:=/;/默认类型是char Active:=true;/默认类型是boolean 2022-7-30943.2.4 常量表达式 常数表达式的形式与高级语言的相似,他们包括字符、数字常量和前面已声明过的符号常量,各种运算符。常量表达式在语
43、法上仍是常量。2022-7-3095 -(一元运算符)对对“-”后的表达式取负后的表达式取负 *乘法 div 整数除法 整数除以整数,取商的整数整数除以整数,取商的整数 mod 求余 整数除以整数,取余数整数除以整数,取余数 /除法 结果是浮点数结果是浮点数 +加法 -减法 2022-7-3096 例13:对于常数表达式,汇编语言在编译程序时计算出值。const x:=10;y:=6;Sum:=x+y;/常量表达式常量表达式HLA在编译时直接翻译常量表达式的值。它不为计算常量表达式“x+y”编译出机器指令,它直接计算这两个常数值的和。从此,在本程序里汇编语言把16和常数Sum联系起来。2022
44、-7-30973.3 变量3.3.1 有符号整型变量3.3.2 无符号整型变量3.3.3 实型变量3.3.4 布尔型变量3.3.5 字符型变量2022-7-3098变量要先定义,后使用。程序员要按照变量的性质,在相应的段中定义变量。定义变量的语法:变量名:数据类型;变量名:数据类型;变量名:数据类型变量名:数据类型:=常量表达式;常量表达式;变量名按标识符取名。变量名按标识符取名。数据类型可以是数据类型可以是HLA的任何一种数据类型。的任何一种数据类型。:=在在语法里是赋值号且只能用于语法里是赋值号且只能用于数据定义数据定义的场合。常量的场合。常量的类型必须与指定的数据类型一致。的类型必须与指
45、定的数据类型一致。2022-7-30993.3.1 有符号整型变量 汇编语言常用的三种长度的有符号的十进制整数类型分别是:int8,int16,int32。分别对应长度为一个字节、两个字节和四个字节的有符号整数。HLA 按照数据类型为每个有符号整数变量分配内存空间。例15:i8:int8;i16:int16;i32:int32;2022-7-30100在声明变量时,可以赋给变量一个初始值,在程序装入内存时由操作系统赋予变量。例16:i8:int8 :=8;i16:int16 :=1600;i32:int32 :=-320000;在赋值号在赋值号(“:=”)后边必须是常数表达式。不后边必须是常数
46、表达式。不能用另一个变量给变量赋值。能用另一个变量给变量赋值。2022-7-301013.3.2 无符号整型变量 HLA常用的三种长度的无符号十进制整数类型分别是:uns8,uns16,uns32。分别对应一个字节、两个字节和四个字节的无符号整数。HLA按照数据类型为每个无符号整数变量分配内存空间。例17:声明无符号整数变量u8:uns8;u16:uns16;u32:uns32;2022-7-30102例18:声明变量时赋初值 u8:uns8:=255;u16:uns16:=6500;u32:uns32:=5900;2022-7-301033.3.3 实型变量 HLA只有三种长度的浮点类型:r
47、eal32(4个字节)代表单精度浮点数,real64(8个字节)代表双精度浮点数,real80(10个字节)代表扩展精度浮点数。汇编语言根据数据类型为每个浮点型变量分配内存空间。系统把浮点类型数值一律当做系统把浮点类型数值一律当做有符号的数值。有符号的数值。2022-7-30104例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;2022-7-301053.3.4 布
48、尔型变量HLA汇编语言程序中可以使用布尔型常量和变量,用布尔型变量或常量组成布尔型表达式,一个布尔型变量是最简单的布尔型表达式。例20:a:boolean;b:boolean:=false;c:boolean:=true;每个布尔型变量占一个字节。你能声明未初始化的变量也能声明初始化的变量。2022-7-301063.3.5 字符型变量你能用char 数据类型声明占一个字节的ASCII字符变量。例21:字符变量的定义c:char;d:char:=A;2022-7-301073.4 程序分段3.4.1 代码段3.4.2 静态数据段3.4.4 堆栈段3.4.5 自动变量段3.4.6 类型段(略)3
49、.4.7 符号常量段(略)3.4.8 在程序中声明段的组织形式(略)3.4.9 数据在内存中存放格式2022-7-301083.4.1代码段汇编语言程序从begin 开始到end 之间的所有指令和数据组成代码段,代码段是一个程序的执行规则,它用指令描述了程序的功能,在代码段里放的是指令及指令中携带的数据根据计算机工作原理,CPU从内存取来第一条指令,执行,然后取下一条指令,再执行直到执行完最后一条指令,程序结束。为了实现程序运行,CPU必须知道指令在哪里,为了帮助CPU找到指令,人们做出了这样设2022-7-30109计,在CPU中设置一个指令计数器EIP,用它放下条指令的偏移地址,再用一个寄
50、存器保存段起始地址的索引,这是硬件必须提供的支持,在80X86中代码段起始地址的索引由操作系统在装入程序时放入CS 中。段寄存器CS中的索引值指向代码段描述符,代码段描述符中包括了段的32位起始地址(段基址)、段的长度、段的属性等内容。2022-7-30110用指令计数器EIP存放下一条指令在代码段中的偏移地址,指令的内存地址(线性地址)是:线性地址=段基址(32位)+偏移地址(32位)在Windows控制下,线性地址通过页表换算出物理地址。在32位汇编语言程序中很难看到段寄存器,因为它们被操作系统封装起来了。任何一个段的起始地址是该段的最小地址,所以偏移地址必须是正数。每取一条指令,EIP自