(完整)32位汇编语言程序设计17稿b_第1页
(完整)32位汇编语言程序设计17稿b_第2页
(完整)32位汇编语言程序设计17稿b_第3页
(完整)32位汇编语言程序设计17稿b_第4页
(完整)32位汇编语言程序设计17稿b_第5页
已阅读5页,还剩799页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、32位汇编语言程序设计计算机科学与信息工程学院 赵建州7/22/20221前 言32位汇编语言程序设计是计算机软件课程。也是计算机专业学生的必修课程,与其他程序设计语言相比,汇编语言对机器的硬件层封装最少,在操作系统的控制下允许程序员最大限度地直接访问计算机硬件。汇编语言从语言的角度逼真地描述了微处理器的体系结构,从软件角度描述了计算机系统硬件层的运行规则。不同的CPU体系有不同的汇编语言。本课介绍的是Intel 80X86CPU系列的32位汇编语言。 7/22/20222在学习计算机专业其他课程时,会遇到一些该课程不能解答的问题:常数为什么不能修改,数据为什么要有数据类型,指针为什么也要有数

2、据类型,为什么C/C+语言中数组的下标从0 开始,为什么不能用值传递参数或自动局部变量从函数带回信息,函数的形参变量和自动局部变量放在内存的哪一部分,它们为什么会随着函数的结束而消失, C/C+语言中为什么要区分整数运算和浮点数运算等等,通过学习32位汇编语言程序设计,会帮助你理解许多其他课程留下的问题。7/22/20223 第一章 汇编语言单词 第二章 CPU映像和机器数 第三章 内存数据映像 第四章 操作数寻址方式第五章输入输出函数 第六章 整型运算 第七章 整型控制结构结束放映7/22/20224 第八章 浮点型运算 第九章 指针和字符串 第十章 数组和串第十二章 过程 结束放映7/22

3、/20225第一章 汇编语言单词1.1 汇编语言字符集和单词1.2 注释符1.3 专用符号1.4 保留字1.5 标识符1.6 汇编语言程序格式7/22/202261.1 汇编语言字符集和单词汇编语言采用ASCII码字符作为自己语言的字符集。 汇编语言的单词由一个或多个ASCII码字符组成,它们对于汇编程序有预定的语法意义。汇编语言的单词包括注释符、专用符号、保留字、标识符等。7/22/202271.2 注释符 汇编语言的注释符分单行注释符和跨行注释符。单行释符 / 可以放在程序某行中任何位置,编译程序忽略从 / 开始到行尾的所有内容。 跨行注释符 /* */ 编译程序忽略从 /* 开始到 */

4、 之间的所有内容。7/22/20228例1:注释的用法 (1)跨行注释符 /* 下面的程序段对数组 实施快速排序算法 */ mov ( 365 , ecx); /* 给计数器赋初值 */ (2)单行注释符 mov ( 365 , ecx); / 给计数器赋初值7/22/202291.3 专用符号专用符号主要包括汇编语言的运算符、分隔符、数制标识符。专用符号有一个字符的也有两个字符的。下面是一个字符的专用符号。 * / + - ( ) : ; , . = & | ! $ % 下面是两个字符的专用符号。 & | = != = := . 7/22/202210例2:专用符号举例 mov( &data

5、 , eax ); stdout.put( 32位汇编语言, nl ); stdout.put(pi=,pi:10:3, nl ); stdout.put( $6f, nl ); stdout.put( % 10101010, nl ); 7/22/2022111.4 保留字 保留字也称关键字,保留字包括 CPU中的寄存器名,汇编语言的指令助记符,语句,数据类型名称等。汇编语言的保留字不区分大小写。7/22/202212 CPU中的寄存器名AL AH AX EAX BL BH BX EBX CL CH CX ECX DL DH DX EDX SI ESIDI EDIBP EBPSP ESPST

6、0 ST1 ST2 ST3 ST4 ST5 ST6 ST77/22/202213 指令助记符和语句ADD INC ADCSUB DEC CMP NEG SBBMUL IMUL INTMUL DIV IDIV MOD IMODIF ELSE ENDIFWHILE ENDWHILE FOR ENDFORFOREVER ENDFOR REPEAT UNTIL 7/22/202214 数据类型名称int8 int16 int32uns8 uns16 uns32real32 real64 real80byte word dword qword lword char string cset array b

7、oolean7/22/202215 其他符号 program begin end procedure type val static var readonly const 如果想了解汇编语言专用符号和保留字的更多的相关信息,请参考HLA手册。 7/22/2022161.5 标识符标识符可用作程序名、变量名、常量名、函数名、过程名、标号等。汇编语言的标识符必须以字母或下划线开始,后面可跟字母、数字、下划线。由于受MASM的限制,标识符的长度不能超过236个ASCII字符。汇编语言的标识符区分大小写字母。 标识符不能与保留字同名。7/22/202217 例3:合法的标识符和非法的标识符(1)合法的

8、标识符 addtion big first last a1 s1 small Small(2)非法的标识符 %a1 5s AL s17/22/2022181.6 汇编语言程序格式 program 程序名; begin 程序名; / 代码段 end 程序名;7/22/202219 程序中的program,begin,end 是汇编语言的保留字。程序名要按标识符取名。声明段用来声明各种变量、常量为它们赋予初值;还用来声明过程。begin和end之间是代码段。 汇编语言提供了输入输出标准库,为了使用输入输出标准库,必须在程序开始用包含语句把标准库的头文件stdlib.hhf包含到程序中来。 7/22

9、/202220例3:显示“汇编语言编程开始了!” 的汇编语言程序program HelloWorld;#include( stdlib.hhf ) / 包含标准库头文件begin HelloWorld;stdout.put( 汇编语言编程开始了!, nl );stdout.put( “击回车键退出 );stdin.readLn();end HelloWorld;7/22/2022217/22/2022227/22/2022237/22/202224如果用C+编写同样的程序,编写的代码如下:#include stdafx.h#include stdio.hint main(int argc, c

10、har* argv)printf(汇编语言编程开始了!n);return 0;7/22/202225#include stdafx.h#include iostreamusing namespace std;int main(int argc, char* argv)cout汇编语言编程开始了!endl;return 0;7/22/202226汇编语言程序具有占用空间小,运行效率高的优点,与这个汇编语言程序相似的C/C+程序经编译后产生的执行代码约有152KB,而汇编语言编译的结果不到8K,汇编语言程序常用于嵌入系统,控制系统编程,也用于编写设备驱动程序,而设计图形界面不是汇编语言的特长,每种

11、程序语言都各有擅长,在应用中注意要扬长避短。7/22/202227第二章 机器数和CPU映像2.1 整数机器数编码2.2 机器整数的加减法运算及溢出问题2.3 字符机器数编码2.4 Intel 80 x86 CPU映像7/22/2022282.1整数机器数编码 汇编语言语法把二进制整数分为两种,无符号和有符号整数。无符号整数是指数据的每一位都代表数值。在汇编语言程序设计里,内存地址(指针),循环次数,ASCII 码等都是无符号整数。数学运算中整数值有正数和负数之分,在计算机元件级怎样表示正号和负号?答案是只能用数字表示正号和负号。因此必须进行符号和数值混合编码。 7/22/202229 (一)

12、原码表示法 如果正数的符号用0 表示,负数的符号用1 表示,绝对值用二进制数表示,这就是原码表示法。假设计算机字长是n 位,能表示n-1位有符号整数,设X=Xn-2Xn-3X0,原码表示是: 0Xn-2Xn-3X0 X 0X源码= 1Xn-2Xn-3X0 X 07/22/202230例1:设n=8,求二进制数10010, -10010的原码。二进制数 10010的原码是00010010,在此最高位的0代表 + 号。二进制数-10010的原码是10010010,在此最高位的1代表 号。根据定义, 0 在原码中有两种表示,所以计算机内整数不采用原码表示法。7/22/202231 (二)补码表示法

13、n位二进制补码的定义是: X 0 X2n-1-1X补码= 2n+X -2n-1X0X是n-1位二进制整数7/22/202232二进制数转换为补码二进制正数转换成补码与原码相同。二进制负数转换成补码有两种方法:方法1:根据定义求补码例2:n=8,求( -1010111) 2和-119的补码。-1010111补码 = 28-1010111 =100000000-1010111 =10101001 -119补码 = 28-1110111 =100000000-1110111 =10001001 100000000 1010111 10101001 100000000 1110111 10001001

14、7/22/202233 方法2:写出负数的绝对值,求绝对值的补码,然后对每位取反(包括符号位),末位加1。例3:n=8,求(- 1010111)2和-119的补码。 计算(- 1010111)2 的补码1 求负数绝对值 10101112 求补码 01010111 / n位补码 3 取反码 101010004 加1 101010017/22/202234 计算 - 119 的补码1. 十进制换成二进制 - 11101112求负数绝对值 11101113求补码 011101114取反码 100010005末位加1 100010017/22/2022350在补码中只有一种表示法。整数数值在计算机元件

15、级用二进制补码表示。注意补码表示是非对称性的。8位补码表示有符号数的范围是-128127,16位补码表示有符号数的范围是-3276832767 。我们将补码逐位取反,再加1的运算称为求补运算。正数的补码经过求补运算结果是它相反数的补码;负数的补码经过求补运算结果也是它相反数的补码。 7/22/202236从机器数计算它的真值对于正数,直接用权的多项式展开求和。例:已知n=8位,求01001010的真值用权的多项式展开求和:原式=26+23+21=74对于负数,有两种方法,每种方法有多个计算步骤。7/22/202237方法一:根据补码的定义X补码 = 2n+X- X = 2n - X补码 注意X

16、本身是负数。方法二:对负数的补码求补,得到它的绝对值,计算绝对值的权的多项式的和,然后对和实施取负运算。7/22/202238我们看同一个整数补码用不同位数表示时有何差别。例4:求117,-117的8位和16位的补码。 117 的补码n = 8 01110101n = 16 0000000001110101 -117 的补码n = 8 10001011n = 16 1111111110001011从例子中得出:一个8位补码数要变成16位补码数时,只需用它的符号位的值填满高8位。这个操作称为符号扩展。7/22/202239因为在计算机元件级无法区分一个二进制数是有符号的还是无符号的。所以在机器内

17、一个二进制数可代表有符号数,也可代表无符号数。例如:假定n=8位,机器内有个整数 %10001010,它可以代表无符号数138;也可以代表有符号数-118。汇编语言程序员对程序中的整数哪些是无符号的,哪些是有符号的必须一清二楚。7/22/2022402.2 机器整数加减法运算及溢出问题(一)零扩展和符号扩展计算机内整数的加法和减法运算要求参加运算数据的长度要相同。如果参加运算的数据长度不同时,在运算之前要把位数短的扩展为长的,否则运算结果可能是错误的。对于无符号的数,高位部分全部用0填满(零扩展);对于有符号的数,高位部分全部用符号值填满(符号扩展)。加减运算时符号值与数值一样参加运算。7/2

18、2/202241例5:计算两个无符号数加法 1010 + 01100000分析:无符号数位数不同时,位数短的必须进行零扩展,即高4位必须填满0。 1左加数零扩展 000010102加右加数 011000003运算结果 011010107/22/202242例6:计算两个有符号数的加法 00001000 + 1100 即(8+(-4)分析:有符号数位数不同时,必须进行符号扩展。因为右加数最高位是1,代表负号,把它变成8位时,高4位必须填满符号值1。1左加数不变 000010002右加数符号扩展 111111003运算结果 100000100因为数据位指定为8位,进位丢失,和等于00000100即

19、4,结果正确。7/22/202243如果不进行符号扩展,计算两个有符号数加法 00001000+11001左加数不变 000010002右加数不符号扩展 11003运算的结果 00010100结果等于20,显然是错误的。7/22/202244(二)整数加减运算可能出现的溢出问题在计算机内运算与人类运算最大的不同之一是计算机只能用有限位数表示数值。如果运算结果超出了有限位数,称为溢出。溢出是一种错误,运算到此只能中断,要程序员修改程序后,重新编译,再执行。7/22/202245无符号数加减运算和有符号数加减运算都有可能发生溢出。对于无符号数的加法,运算中最高位如产生进位;对于无符号数减法,运算中

20、最高位如产生了借位,这都是溢出。7/22/202246例7:n=8,计算 130+145 1130的机内表示 100000102145的机内表示 100010013运算的结果 100001011 运算中最高位产生进位,由于机器内数据规定是8 位,进位丢失,这就是溢出,结果是错误的。7/22/202247例8:n=8,计算 130-145 1130的机内表示 100000102145的机内表示 100010013运算的结果 11111001 运算中最高位产生借位,由于机器内数据规定是 8 位,借位丢失,这也是溢出,结果是错误的。 7/22/202248根据补码定义和数学公理,有符号数加减法溢出可

21、能发生在两个同号数相加或两个异号数相减的时候。如果两个同号数相加,结果的符号与加数的符号相反;两个异号数相减,结果的符号与减数的符号相同时,这就是溢出。因为,两个正数相加结果绝对不可能是负数;同样一个负数减正数,结果绝对不可能是正数等等7/22/202249例9:n=8, 计算 72+98 172的机内表示 01001000298的机内表示 011000103运算的结果 10101010结果不是正数,而是负数-86。显而易见结果是错误的。7/22/202250例10:n=8, 计算 -83 +(-80)1-83的机内表示 101011012-80的机内表示 101100003运算结果 1010

22、11101由于机器是8位,结果的最高位丢失,结果变成正数93,是错误的。7/22/202251例11:n=8, 计算72-(-98) 1 72的机内表示 010010002- 98的机内表示 100111103 运算的结果 10101010结果与减数符号相同,正数减负数结果是负数。它的值是-86。结果是错误的。7/22/202252例12:n=8, 计算-83 80 1-83的机内表示 101011012 80的机内表示 010100003运算的结果 01011101结果与减数符号相同,负数减正数结果是正数。它的值是93。结果是错误的。 7/22/2022532.3 字符型机器数编码在计算机内

23、,字符也必须用二进制数编码表示。最通用的字符是 ASCII 码字符,它是美国标准信息交换码。它用二进制代码规定了英文字母、阿拉伯数字、算术运算符、英文标点符号和其他常用符号以及控制符号的表示,ASCII 码包括了 128 个字符,具体内容见本书附录1。7/22/202254中国在1980年发表GB2312-80信息交换码标准,这一标准后来被国际标准化组织接纳为国际标准,它是个双字节编码标准,一个汉字用两个字节表示,每个字节只用了低七位,每个字节的最高位值是0。因为ASCII码字符用一个字节的低七位表示,最高位的值也是0,而且它已经是机器数编码了,所以为了在机器里区分汉字和ASCII码,在机器里

24、把汉字的GB2312码的每个字节的最高位的值规定为1后作为汉字的机器码。7/22/202255例13:输出汉字的机器码例如汉字“水”,它的机器码值是$AE_CB,要把机器码变成GB2312-80码,用机器码减$80_80即可,“水”字的GB2312码值是$2E_4B。7/22/2022562.4 Intel 80 x86映像Intel 80 x86 CPU 系列属于Von Neumann结构的机器,Von Neumann 计算机体系结构包括三个主要部分:中央处理单元(CPU),存储器,输入/输出设备(I/O)。这三部分由系统总线连在一起,见图2.1。系统总线包括控制总线、数据总线、地址总线。7

25、/22/202257中央处理机 CPU总线控制 逻辑接 口接 口内 存 大容量外存储器I/O设备I/O子系统系统总线.图 2.1 计算机硬件结构 7/22/202258从80486开始,Intel 把浮点运算协处理器集成到CPU内,在CPU内称它为浮点运算单元(FPU),现暂不介绍浮点运算单元。CPU内部最显著的部件是寄存器。Intel CPU寄存器可分为四类:段寄存器,内核模式专用寄存器,通用寄存器,应用程序可访问的专用寄存器。7/22/202259 段寄存器组包括CS、DS、SS、ES、FS、GS等6个16位寄存器。CS是代码段寄存器,SS是堆栈段寄存器,其余的是数据段寄存器。 内核模式专

26、用寄存器供系统编程使用,这里不做介绍。 7/22/202260 图2.2 80 x86通用寄存器7/22/202261通用寄存器组包括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, DL和DH Intel CPUs的这些寄存器不都是独立的寄存器, 当修改一

27、个寄存器时则至少同时修改了另一个寄存器。7/22/202262 应用程序可访问的专用寄存器(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保留7/22/202263Bit 7 SF 运算结果最高位是1时置1Bit 8 TF 如置1每执行一条指令发生中断Bit 9 IF 如置1允许响应可屏蔽中断Bit 10 DF 请

28、参考第十一章Bit 11 OF 指令执行后发生溢出时置17/22/202264 很多指令执行后会影响条件标志,尤其在进行加减运算时,CPU并不知操作数是有符号还是无符号数,它只是按照运算结果设置条件标志,需要程序员自己来判断运算结果是否正确。7/22/202265例14:计算 01001011+00111000 左加数 01001011 右加数 00111000 相加结果 10000011运算结果使AF=1,OF=1,SF=1,ZF=0,CF=0,PF=0。如果这两个数是无符号数,运算结果是正确的,因为没发生溢出(CF=0);如果这两个数是有符号数,运算结果是错误的,因为发生了溢出(OF =

29、1)。这要由程序员自己判断。计算机硬件不保证运算结果是否正确,只负责按结果设标志。7/22/202266(2)指令计数器EIP指令计数器EIP是32位寄存器,它存放着下一条要执行的机器指令的偏移地址。程序装入内存时,由操作系统负责把第一条指令的偏移地址装入EIP,CPU每取一条指令就自动修改EIP,将它的值变成下一条指令的偏移地址。由于EIP起着直接保证程序正确执行的关键作用,在80 x86指令集中看不见EIP7/22/202267偏移地址是为了方便计算机内存系统管理而引入的一个逻辑地址概念,因为程序员在编程时,无法知道将来程序运行时放在内存的哪个位置,所以让编译程序在编译源程序时,以字节为单

30、位按顺序给每条指令、每个数据赋予一个逻辑地址,并且每个段都从零开始编址,这个逻辑地址就称作偏移地址。在程序执行中,由内存管理机构将逻辑地址映射到真正的物理地址。这部分内容将在寻址方式一章中介绍。指令B指令A代码段047/22/202268(3)堆栈指针寄存器ESP32位寄存器ESP它只用来作为堆栈栈顶指针。它是栈顶的偏移地址。堆栈操作指令都以它的值访问堆栈。(4)堆栈指针、数据寄存器EBP32位EBP寄存器除了可用作数据寄存器外,还可用作访问堆栈的指针寄存器,也是具有特殊用途的寄存器。 7/22/202269 堆栈段栈顶指针 ESP基址指针EBP016k7/22/202270第三章 内存数据映

31、像3.1 基本数据类型3.2 常量3.3 变量3.4 程序分段7/22/2022713.1 基本数据类型 汇编语言基本数据类型uns8 无符号的8位整数uns16 无符号的16位整数uns32 无符号的32位整数int8 有符号的8位整数int16 有符号的16位整数int32 有符号的32位整数boolean 布尔型,占一个字节char 字符类型,占一个字节7/22/202272real32 32位浮点数real64 64位浮点数real80 80位浮点数byte 通用的8位类型tbyte 通用的80位类型word 通用的16位类型dword 通用的32位类型qword 通用的64位类型lw

32、ord 通用的128位类型7/22/202273 汇编语言复合数据类型 string 字符串(字符串变量实际是4个字节长的指针)text 与字符串相似,文本常数常用于指令中,减小输入击键次数7/22/2022743.2 常量3.2.1 数值常数和布尔型常数3.2.2 字符串和字符常量3.2.3 符号常量3.2.4 常量表达式7/22/202275常量是编译程序时,已经有确定的值,在程序运行中这个值不能改变。每个常量具有数据类型,常量的类型可以用HLA的任何一种类型。注意语法认为常量的数据类型是不明确的。 7/22/2022763.2.1 数值常数和布尔型常数 十进制整数进位计数制是常用的计数方

33、法。人们习惯使用十进制,每位的数字可以是0到9中的任何一个,它的基数是十,计数时逢十进一。这也是十进制的名称由来。7/22/202277在程序里可以用十进制整数。例1:123, 32_123, 0, -23高级汇编语言允许数值中用下划线作为分隔符,便于人们阅读。从语法上讲,数值前可有正号或负号,数值中允许有下划线,从语法上讲,下划线的位置可以在任意两个数字之间,在实际应用中将下划线作为千分号,使人们阅读方便。 7/22/202278二进制整数 在数字电子计算机内,每位数字要用一个电子元件(如晶体管)的一个物理状态来表示,通常一个电子元件存在两种稳定的状态(如晶体管的饱和与截止),而一位二进制也

34、存在两种状态0和1。一个电子元件恰好可以表示一位二进制,所以在数字电子计算机内使用二进制。一个数值无论用二进制还是十进制表示,其本质是代表一个值。 7/22/202279在程序里可以用二进制整数。高级汇编语言要求以 % 前缀开始,不能带符号。例2:%1101_0001高级汇编语言允许在数值中用下划线作为分隔符,便于人们阅读。 7/22/202280n位m进制可以表示mn种状态。如三位二进制可以表示23种状态: %000 %001 %010 %011 %100 %101 %110 %1117/22/202281十六进制整数用二进制表示数字对程序员来讲阅读和书写都不方便,为了方便阅读和书写程序,在

35、汇编语言源程序里还可以用十六进制表示数值。汇编语言要求以 $ 前缀开始,不能带符号。例3:$123, $12_1ae6高级汇编语言允许在数值中用下划线作为分隔符,便于人们阅读。7/22/202282在汇编语言源程序里程序员可以用上面三种数制中的任何一种表示自己的数据,其实机器只识别二进制,源程序中用非二进制表示的数由汇编程序或编译程序转换成二进制数。7/22/202283(4) 实型常数 HLA的浮点类型常数表示如下:(1)一个“+” 或 “-”表示尾数的符号。如没有 符号,HLA默认它是正数。(2)跟随一位或多位十进制数。(必选项)(3)跟随小数点和一位或多位十进制数(可 选项)。(4)跟随

36、一个“e”或“E”,其后是符号(“+”或 -)和一位或多位十进制数。7/22/202284必须有小数点或”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 7/22/202285布尔常数 HLA预定义两个布尔型常数,true 和false在内部,HLA定义true 和false值分别是1和0。HLA默认为每个布尔

37、型常量分配一个字节。实际上布尔操作只看布尔值的#0位而把其他位清零。你不能像在C/C+语言中在用布尔表达式的地方用整型表达式。7/22/2022863.2.2 字符串和字符常量 (1)字符串常量 字符串常量是用双引号括住的零个或多个字符。例5: 32位汇编语言 a 123性质1:HLA自动将程序中相邻的字符串联接起来。性质2:在字符串常量中插入两个双引号来代表一个 双引号。7/22/202287(2)字符常量格式1:用两个单引号括住的一个ASCII码字 符。格式2:#整数常数。 整数常数可以用十进制、十六进制或二进制,代表字符的ASCII码值。数值在0到255的范围内,但只显示32到127范围

38、内的字符。如果指定的数值超过0到255的范围,系统在编译时会报错。系统默认为每个字符常量分配一个字节。7/22/202288性质1:在两个单引号中放两个单引号代表一个单引号。性质2:HLA可以联接任何相邻的字符常量和字符串常量组成一个字符串常量在程序中,语法认为字符常量的数据类型是不明确的。7/22/202289例7: 2 ,a ,#13,#$d,#%1101上面第三个字符表示一个单引号,后面的三个字符都代表回车 。记住在程序中“a” 和 a是不相同的。7/22/2022903.2.3 符号常量 在HLA的CONST段声明符号常量。该段中声明的常量的值从编译到运行都不会改变;该段位于程序中的声

39、明段位置。它以CONST保留字开始。 CONST 标识符 :数据类型 := 常数表达式; 标识符 := 常数表达式; 第二种格式是省略数据类型的语法格式,此时系统自动赋予默认数据类型。HLA按数据类型为符号常量分配内存空间。 7/22/202291 在CONST段声明常量时,必须对其初始化。 := 在语法里是赋值号且只能用于数据定义的场合。在程序运行中,不允许对CONST段中的对象进行修改。在CONST段中声明字符串常量可以省略数据类型,但文本常量不能省略数据类型。 虽然,声明符号常量时,设置了数据类型,这里数据类型仅仅是为给常量分配内存单元而设置的,在指令中,语法仍然认为符号常量的数据类型是

40、不明确的7/22/202292例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 7/22/2022933.2.4 常量表达式 常数表达式的形式与高级语言的相似,他们

41、包括字符、数字常量和前面已声明过的符号常量,各种运算符。常量表达式在语法上仍是常量。 7/22/202294 - (一元运算符) 对“-”后的表达式取负 * 乘法 div 整数除法 整数除以整数,取商的整数 mod 求余 整数除以整数,取余数 / 除法 结果是浮点数 + 加法 - 减法 7/22/202295 例13:对于常数表达式,汇编语言在编译程序时计算出值。const x:= 10; y:= 6; Sum:= x + y; / 常量表达式HLA在编译时直接翻译常量表达式的值。它不为计算常量表达式“x+y”编译出机器指令,它直接计算这两个常数值的和。从此,在本程序里汇编语言把16和常数Su

42、m联系起来。 7/22/2022963.3 变量3.3.1 有符号整型变量3.3.2 无符号整型变量3.3.3 实型变量3.3.4 布尔型变量3.3.5 字符型变量7/22/202297变量要先定义,后使用。程序员要按照变量的性质,在相应的段中定义变量。 定义变量的语法: 变量名:数据类型; 变量名:数据类型 := 常量表达式;变量名按标识符取名。数据类型可以是HLA的任何一种数据类型。:= 在语法里是赋值号且只能用于数据定义的场合。常量的类型必须与指定的数据类型一致。 7/22/2022983.3.1 有符号整型变量 汇编语言常用的三种长度的有符号的十进制整数类型分别是:int8, int1

43、6,int32。分别对应长度为一个字节、两个字节和四个字节的有符号整数。HLA 按照数据类型为每个有符号整数变量分配内存空间。 例15:i8:int8;i16:int16;i32:int32;7/22/202299在声明变量时,可以赋给变量一个初始值,在程序装入内存时由操作系统赋予变量。例16:i8:int8 :=8;i16:int16 :=1600;i32:int32 :=-320000; 在赋值号(“:=”)后边必须是常数表达式。不能用另一个变量给变量赋值。7/22/20221003.3.2 无符号整型变量 HLA常用的三种长度的无符号十进制整数类型分别是:uns8,uns16,uns32

44、。分别对应一个字节、两个字节和四个字节的无符号整数。HLA按照数据类型为每个无符号整数变量分配内存空间。 例17:声明无符号整数变量u8:uns8; u16:uns16; u32:uns32; 7/22/2022101例18:声明变量时赋初值 u8:uns8:=255; u16:uns16:=6500; u32:uns32:=5900;7/22/20221023.3.3 实型变量 HLA只有三种长度的浮点类型: real32 (4个字节) 代表单精度浮点数, real64(8个字节) 代表双精度浮点数, real80(10个字节)代表扩展精度浮点数。 汇编语言根据数据类型为每个浮点型变量分配内

45、存空间。系统把浮点类型数值一律当做有符号的数值。7/22/2022103例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; 7/22/20221043.3.4 布尔型变量HLA汇编语言程序中可以使用布尔型常量和变量,用布尔型变量或常量组成布尔型表达式,一个布尔型变量是最简单的布尔型表达式。例20:a:boolean; b:bo

46、olean := false; c:boolean := true; 每个布尔型变量占一个字节。你能声明未初始化的变量也能声明初始化的变量。 7/22/20221053.3.5 字符型变量你能用char 数据类型声明占一个字节的ASCII字符变量。例21:字符变量的定义c: char; d: char := A; 7/22/20221063.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 数据在内存中存放格式7/22/20221073.4.1代码

47、段汇编语言程序从begin 开始到end 之间的所有指令和数据组成代码段,代码段是一个程序的执行规则,它用指令描述了程序的功能,在代码段里放的是指令及指令中携带的数据根据计算机工作原理,CPU从内存取来第一条指令,执行,然后取下一条指令,再执行直到执行完最后一条指令,程序结束。为了实现程序运行,CPU必须知道指令在哪里,为了帮助CPU找到指令,人们做出了这样设7/22/2022108计,在CPU中设置一个指令计数器EIP,用它放下条指令的偏移地址,再用一个寄存器保存段起始地址的索引,这是硬件必须提供的支持,在80X86中代码段起始地址的索引由操作系统在装入程序时放入CS 中。段寄存器CS中的索

48、引值指向代码段描述符,代码段描述符中包括了段的32位起始地址(段基址)、段的长度、段的属性等内容。7/22/2022109用指令计数器EIP存放下一条指令在代码段中的偏移地址,指令的内存地址(线性地址)是: 线性地址 = 段基址(32位) + 偏移地址(32位) 在Windows控制下,线性地址通过页表换算出物理地址。在32位汇编语言程序中很难看到段寄存器,因为它们被操作系统封装起来了。任何一个段的起始地址是该段的最小地址,所以偏移地址必须是正数。每取一条指令,EIP自动修改,指向下条指令的地址。7/22/2022110012315CS寄存器索引字0TIRPL7/22/2022111偏移地址是

49、为了方便计算机内存系统管理而引入的一个逻辑地址概念,因为程序员在编程时,无法知道将来程序运行时放在内存的哪个位置,所以让编译程序在编译源程序时,以字节为单位按顺序给每条指令、每个数据赋予一个逻辑地址,并且每个段都从零开始编址,这个逻辑地址就称作偏移地址。在程序执行中,由内存管理机构将逻辑地址映射到真正的物理地址。指令B指令A代码段04EIPEIP7/22/2022112 偏移地址 内 存 代码段基址B EIPB + EIP 低地址端 高地址端7/22/20221133.4.2静态数据段 在静态(STATIC)内存段声明的变量称静态变量,如果没有初始化,系统默认用0作变量的初值。在装入程序时给静

50、态数据段配内存,到程序结束时,和代码段同时撤内存。7/22/2022114 汇编语言定义了取变量偏移地址的运算,语法是: & 静态变量运算的结果是该静态变量的偏移地址,它的长度是32位。7/22/2022115例23:计算静态变量的偏移地址 mov( & b , eax); 指令将变量b的偏移地址装入寄存器EAX7/22/2022116除了定义静态变量外,你还可使用伪操作码byte, word, dword, uns32等,把数据插入静态内存段。7/22/2022117例24:插入数据static b:byte := 0; / 为每个数据分配1个字节byte 1,2,3; u:uns32 :=

51、 1; / 为每个数据分配4个字节uns32 5,2,10; HLA在变量定义后,使用伪操作码将数据写入静态内存段。如字节值 1、2、3嵌入变量b 字节之后。这些值没有变量名,在学习寻址方式时,将讨论怎样访问没有变量名的值。插入的数据在内存怎样存放?7/22/2022118 0 1 2 3 &b+0 &b+1 &b+2 &b+3 偏移地址 内 存 &u+12 偏移地址 内 存 &u+8 &u+0 &u+4102 51 段基址 段基址7/22/2022119为变量分配地址但不分配空间STATIC段里 变量的NOSTORAGE属性表示在数据段给变量赋予当前的地址,但不给变量分配内存空间,所以变量与

52、段里的下一个对象共用同一个地址,语法表示如下: 变量名:类型;nostorage; 7/22/2022120例25:static x: dword; nostorage; byte a, b, c, d; 假定变量x 的地址是 1120,则数据a的地址也是1120,数据b的地址是1121,数据c的地址是1122,数据d的地址是1123。插入的数据是这样存放的:7/22/20221211123abcd内存变量x与后面的4个数据共享内存空间。数据a的偏移地址= 1120 + 0数据b的偏移地址= 1120 + 1数据c的偏移地址= 1120 + 2数据d的偏移地址= 1120 + 31122112

53、11120 x7/22/20221223.4.4堆栈段堆栈段是用先进后出的动态数据结构维护的一个内存区。段寄存器SS中的索引值指向堆栈段描述符,描述符保存了段的起始地址(32位段基址 ),而指针寄存器ESP值是当前栈顶的偏移地址。由CPU的内存管理组件把栈顶的逻辑地址映射为线性地址。系统默认为你的程序建立堆栈段,为它分配16MB空间。7/22/2022123 偏移地址 内 存 堆栈段基址B 栈底 栈顶 espB + esp 低地址端 高地址端 B + 16M 初始栈顶栈顶是浮动的而栈底是固定的7/22/20221243.4.5自动变量段VAR段在堆栈段里分配内存空间。主程序里声明的var 段与

54、static段具有同样的生命周期。汇编语言不允许对VAR段的变量初始化。系统也不会对VAR段的变量初始化。7/22/2022125例27: var a:int32; c:char; 7/22/20221263.4.7 符号常量段HLA的CONST段用来声明符号常量。CONST段中声明的常量其值从编译到运行都不会改变;CONST段位于程序中的声明段位置。它以CONST保留字开始。例:const x:= 10; y:= 6; Sum:= x + y; / 常量表达式7/22/2022127例30:在CONST段声明文本常量。const i: text := (type int32 edi); j:

55、 text := (type int32 esi); Middle: text := (type uns32 edx); mov( i, eax ); / mov(type int32 edi , eax);add( j, eax ); / add(type int32 esi , eax);shr( 1, eax ); mov( ebx+eax*4, Middle ); / 把中间值装入EDX 7/22/2022128当HLA汇编源程序时,遇见符号文本常量时,它用那个文本替换标识符(而不是字符串常数),然后继续编译。这能节省键盘输入时间,也使程序容易阅读。汇编上面的源程序段时,汇编程序把源程

56、序段先翻译成以下的样子:mov(type int32 edi), eax ); add(type int32 esi), eax ); shr( 1, eax ); mov( ebx+eax*4, (type uns32 edx) );7/22/20221293.4.9数据在内存中存放格式 80X86系列的内存每个字节有一个地址,由于指令和数据长度少则一个字节,多则多个字节。如果数据就占一个字节,这个字节的地址就是数据的地址;如果一个数据或一条指令占多个字节(操作系统会为它分配连续的地址空间),操作系统就按低地址作为数据或指令的地址,并遵循低位数据(指令)装入低地址字节,高位数据(指令)装入高

57、地址字节的规则将数据或指令装入内存。 7/22/2022130如字节型数据值是A,字类型数据值是$1256双字类型数据值是$106f3a6e。三个数据的地址分别是186、188、192。数据如图存放: 低放低, 高放高。7/22/2022131例:数据在寄存器中存放格式如有数据$ 1234abcd要放在寄存器EAX中,根据规则存放的结果是: 1 2 3 4 a b c dEAXALAH7/22/2022132例:如有数据$ 1234abcd要放在地址是1200的内存单元中,根据规则存放的结果是: 1 2 3 41200 a b c d1201120212037/22/2022133第四章 寻址

58、方式汇编语言的指令按其指令格式包含的操作数的个数可以分为:无操作数、单操作数、双操作数三种形式: 指令助记符( ); 指令助记符(源操作数/目的操作数); 指令助记符(源操作数,目的操作数); 7/22/2022134操作数在指令中最多要表达三种含义:1. 表示操作数的值(数值或字符)2. 表示操作数所在的位置(内存、指令、中央处理器)3. 表示操作数的数据类型至少要表达二种含义即 1.和2.,其中2. 是汇编语言独有的,它要明确地表示操作数在哪里,使CPU可以准确地取到操作数。7/22/2022135 指令助记符表示指令能产生的操作,常用英文的缩写表示。如“add”代表“addition ”

59、(加法)。“sub ”代表“subtracting ”(减法)。 源操作数参加运算后其值不变,通常目的操作数参加运算后又用来存放运算结果。指令中的操作数必须用寻址方式表示。下面我们以操作数所处的位置分类学习操作数的寻址方式。7/22/2022136 4.1 寄存器寻址方式 4.2 立即寻址方式 4.3 保护模式的内存寻址方式 4.4 数据类型限制7/22/20221374.1 寄存器寻址方式 操作数格式: 寄存器名 寄存器名是任何一个通用寄存器的名字。寄存器的内容就是指令需要的操作数。7/22/2022138例1:mov( EBX, EAX ); / 将源操作数 ebx 值复制给目的操作数 e

60、ax 2F67 2F67 547A 547A EBX EAX7/22/2022139 inc( ecx); 13AF 26446679ABCD13AF 2645执行前的ECX执行后的ECX 13AF2644 + 17/22/20221404.2 立即寻址方式操作数格式: 常数或常数表达式 常数值就是指令的操作数的值,它包含在指令中,当从内存取来这样的指令,指令中就包括了操作数。 在所有寻址方式里,这种方式的访问时间是最短的。 但它天生的缺陷是在程序运行中不能修改操作数。7/22/2022141 例2: mov( -50, AX ); /* 源操作数是立即寻址方式,目的操作数是寄存器寻址方式 *

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论