ImageVerifierCode 换一换
格式:DOCX , 页数:45 ,大小:37.46KB ,
资源ID:9204854      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9204854.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(汇编语言之程序的基本结构.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

汇编语言之程序的基本结构.docx

1、汇编语言之程序的基本结构第6章 程序的基本结构在前面几章,我们分别介绍了用汇编语言进行程序设计所需要的几个最基本的知识:内存单元的寻址方式,变量定义和各种汇编指令格式。在掌握了这些基本内容之后,就需要学习如何把它们组成一个完整的汇编语言程序。6.1 源程序的基本组成汇编语言源程序的组成部分有:模块、段、子程序和宏等。一个模块对应一个目标文件,当开发较大型的应用程序时,该程序可能由若干个目标文件或库结合而成的。有关模块和子程序的知识和宏在第7章介绍,有关宏的知识将在第9章中叙述。6.1.1 段的定义微机系统的内存是分段管理的,为了与之相对应,汇编语言源程序也分若干个段来构成。8086CPU有四个

2、段寄存器,在该系统环境下运行的程序在某个时刻最多可访问四个段,而80386及其以后的CPU都含有六个段寄存器,于是,在这些系统环境下开发的运行程序在某个时刻最多可访问六个段。不论程序在某个时刻最多能访问多少个段,在编程序时,程序员都可以定义比该段数更多的段。在通常情况下,一个段的长度不能超过64K,在80386及其以后系统的保护方式下,段基地址是32位,段的最大长度可达4G。段的长度是指该段所占的字节数:、如果段是数据段,则其长度是其所有变量所占字节数的总和;、如果段是代码段,则其长度是其所有指令所占字节数的总和。在定义段时,每个段都有一个段名。在取段名时,要取一个具有一定含义的段名。段定义的

3、一般格式如下:段名SEGMENT对齐类型 组合类型 类别;段内的具体内容段名ENDS其中:“段名”必须是一个合法的标识符,前后二个段名要相同。可选项“对齐类型”、“组合类型”和“类别”的说明作用请见6.3节中的叙述。一个数据段的定义例子:DATA1SEGMENTword1DW1, 9078H, ?byte1DB21, WorldDD12345678HDATA1ENDS一个代码段的例子:CODE1SEGMENTMOVAX, DATA1;把数据段DATA1的段值送AXMOVDS, AX;把AX的值送给DS,即:DS存储数据段的段值MOVAX, 4C00HINT21H;调用DOS功能,结束程序的运行

4、CODE1ENDS6.1.2 段寄存器的说明语句在汇编语言源程序中可以定义多个段,每个段都要与一个段寄存器建立一种对应关系。建立这种对应关系的说明语句格式如下:ASSUME 段寄存器名:段名, 段寄存器名:段名, 其中:段寄存器是CS、DS、ES、SS、FS和GS,段名是在段定义语句说明时的段名。在一条ASSUME语句中可建立多组段寄存器与段之间的关系,每种对应关系要用逗号分隔。例如,ASSUME CS:CODE1, DS:DATA1上面的语句说明了:CS对应于代码段CODE1,DS对应于数据段DATA1。在ASSUME语句中,还可以用关键字NOTHING来说明某个段寄存器不与任何段相对应。下

5、面语句说明了段寄存器ES不与某段相对应。ASSUME ES:NOTHING在通常情况下,代码段的第一条语句就是用ASSUME语句来说明段寄存器与段之间的对应关系。在代码段的其它位置,还可以用另一个ASSUME语句来改变前面ASSUME语句所说明的对应关系,这样,代码段中的指令就用最近的ASSUME语句所建立的对应关系来确定指令中的有关信息。例6.1 汇编语言段及其段说明语句的作用。DATA1SEGMENT;定义数据段DATA1word1DW5678hbyte1DBABCDEFGDATA1ENDSDATA2SEGMENT;定义数据段DATA2word2DW1234hword3DW9876hDAT

6、A2ENDSDATA3SEGMENT;定义数据段DATA3byte2DB?DATA3ENDSCODE1SEGMENT;编写代码段CODE1ASSUMECS:CODE1, DS:DATA1, ES:DATA2;(1)MOVAX, DATA1;(2)MOVDS, AX;(3)MOVAX, DATA2;(4)MOVES, AX;(5)MOVAX, word1;访问段DATA1中的字变量word1MOVword2, AX;访问段DATA2中的字变量word2ASSUMEDS:DATA3, ES:NOTHING;(6)MOVAX, DATA3MOVDS, AXMOVBL, byte2;访问段DATA3中

7、的字节变量byte2MOVAX, 4C00H;(7)INT21H;(8) CODE1ENDS语句(1)和(6)分别说明了段和段寄存器之间的对应关系,其中语句(6)重新说明语句(1)所指定的对应关系。二组语句(2)和(3)、(4)和(5)实现对段寄存器DS和ES赋初值。ASSUME说明语句只起说明作用,它不会对段寄存器赋值,所以,必须对有关段寄存器赋值。在以后的其它源程序中也都是用此方法来实现对数据段寄存器赋值的。语句(7)和(8)是调用中断21H的4CH号功能来结束本程序的执行,程序的返回代码由寄存器AL来确定。结束本程序执行的指令是所有主模块必须书写的语句。注意:代码段寄存器不能由程序员在源

8、程序中对其赋值,其值是由操作系统在装入它进入系统运行时自动赋值的。6.1.3 堆栈段的说明堆栈段是一个特殊的段,在程序中可以定义它,也可以不定义。除了要生成COM型执行文件的源程序外,一个完整的源程序一般最好定义堆栈段。如果在程序中不定义堆栈段,那么,操作系统在装入该执行程序时将自动为其指定一个64K字节的堆栈段。在程序没有定义堆栈段的情况下,在由连接程序生成执行文件时,将会产生一条如下的警告信息,但程序员可以不理会它,所生成的执行文件是可以正常运行的。warning xxxx: no stack segment (其中:xxxx是错误号)在源程序中,可用以下方法来定义堆栈段。方法1:STAC

9、K1SEGMENTDB256 DUP(?);256是堆栈的长度,可根据需要进行改变TOPLABEL WORDSTACK1ENDS以上堆栈段的定义如图6.1所示。由于堆栈是按地址从大到小的存储单元顺序来存放内容的,所以,在堆栈存储单元说明语句之后,再说明一个栈顶别名,这样,对栈顶寄存器SP的赋值就很方便。在源程序的代码段中,还要添加如下程序段,才能把段STACK1当作堆栈段来使用。图6.1 堆栈段定义示意图ASSUMESS:STACK1;可在代码段的段指定语句中一起说明CLI;禁止响应可屏蔽中断MOVAX, STACK1MOVSS, AXMOVSP, offset TOP;给堆栈段的栈顶寄存器S

10、P赋初值STI;恢复响应可屏蔽中断方法2:STACK1SEGMENTSTACK;定义一个堆栈段,其段名为STACK1DB256 DUP(?)STACK1ENDS上述段定义说明了该段是堆栈段,系统会自动把段寄存器SS和栈顶寄存器SP与该堆栈段之间建立相应的关系,并设置其初值,而不用在代码段对它们进行赋值。除了以上二种方法外,还有一种更简洁的方法来定义堆栈段,有关内容请见第6.4.2节中的叙述。6.1.4 源程序的结构下面的程序是一个完整的源程序,其功能是在屏幕上显示字符串“Hello, World.”。读者可参考此结构编写自己的简单程序。例6.2 在屏幕上显示字符串“HELLO,WORLD.”解

11、:可运行下面的控件,用鼠标左键单击程序中的某一行,可阅读其含义;单击“内存”可切换内存内容的显示方式。伪指令END表示源程序到此为止,汇编程序对该语句之后的任何内容都不作处理,所以,通常情况下,伪指令END是源程序的最后一条语句。伪指令END后面可附带一个在程序中已定义的标号,由该标号指明程序的启动位置。如果源程序是一个独立的程序或主模块,那么,伪指令END后面一定要附带一个标号;如果源程序仅是一个普通模块,那么,其END后面就一定不能附带标号。6.2 程序的基本结构在学习高级语言程序设计时,我们知道了程序的三大主要结构:顺序结构、分支结构和循环结构。在汇编语言的源程序也同样有此三大结构,所不

12、同的是它们的表现形式不同。用高级语言编写程序时,由于不使用“转移语句”而使这三种结构清晰明了。但在汇编语言的源程序中,很难不使用“转移语句”(除非是一些只有简单功能的程序),有时甚至会有各种各样的“转移语句”。由于存在这些转移语句,就使得:汇编语言源程序的基本结构显得不太明确。如果源程序的编写者思维混乱,编写出来的源程序在结构上就会显得杂乱无章,反之,如果编写者条理清晰,安排的操作井然有序,那么,编写出来的程序在结构上就会一目了然。总之,不论是高级语言的源程序,还是汇编语言的源程序,其程序的三大基本结构也还是万变不离其宗的。6.2.1 顺序结构顺序结构是最简单的程序结构,程序的执行顺序就是指令

13、的编写顺序,所以,安排指令的先后次序就显得至关重要。另外,在编程序时,还要妥善保存已得到的处理结果,为后面的进一步处理直接提供前面的处理结果,从而避免不必要的重复操作。例6.3 编写程序段,完成下面公式的计算(其中:变量X和Y是32位有符号数,变量A,B和Z是16位有符号数)。A(X-Y+24)/Z的商,B(X-Y+24)/Z的余数解:DATA1SEGMENTXDD?YDD?ZDW?ADW?BDW?DATA1ENDSCODE1SEGMENTMOVAX, XMOVDX, X+2;用(DX:AX)来保存32位变量X的数值SUBAX,YSBBDX, Y+2;(DX:AX)-(Y+2:Y)ADDAX,

14、 24DADCDX, 0;(DX:AX)+24IDIVZMOVA, AXMOVB, DXCODE1ENDS在编程序时,常常需要交换二变量之值。假设需要交换值的变量名为:var1和var2,临时增加的变量名为temp。常用的算法如下:temp = var1var1 = var2var2 = temp例6.4 假设有二个字变量word1和word2,编写程序段实现交换其值的功能。解:方法1:用汇编语言指令简单“直译”上面的 交换数据方法DATA1SEGMENTword1DW?word2DW?tempDW?DATA1ENDSCODE1SEGMENTMOVAX, word1MOVtemp, AX;上二

15、语句实现语句“temp=word1”MOVAX, word2MOVword1, AX;上二语句实现语句“word1=word2”MOVAX, tempMOVword2, AX;上二语句实现语句“word2=temp”CODE1ENDS这种方法虽然也能完成功能,但显然其不能充分利用汇编语言的特点,程序效率很低。方法2:用汇编语言指令的特点来直接编译DATA1SEGMENTword1DW?word2DW?DATA1ENDSCODE1SEGMENTMOVAX, word1XCHGAX, word2MOVword1, AX;能XCHG word1, word2来代替这三条指令吗?CODE1ENDS该方

16、法充分利用了汇编语言的特点,不仅省去了中间变量temp的定义,而且程序的效率也提高了。6.2.2 分支结构分支结构是一种非常重要的程序结构,也是实现程序功能选择所必要的程序结构。由于汇编语言需要书写转移指令来实现分支结构,而转移指令肯定会破坏程序的结构,所以,编写清晰的分支结构是掌握该结构的重点,也是用汇编语言编程的基本功。在程序中,当需要进行逻辑分支时,可用每次分二支的方法来达到程序最终分多支的要求,也可是用地址表的方法来达到分多支的目的。一、显示转移指令实现的分支结构在高级语句中,分支结构一般用IF语句来实现,在汇编语言中,课用无条件转移指令或条件转移指令实现的分支结构。如图6.2给出了二

17、种常用的分支结构。在编写分支程序时,要尽可能避免编写“头重脚轻”的结构,即:当前分支条件成立时,将执行一系列指令,而条件不成立时,所执行的指令很少。这样就使后一个分支离分支点较远,有时甚至会遗忘编写后一分支程序。这种分支方式不仅不利于程序的阅读,而且也不便将来的维护。所以,在编写分支结构时,一般先处理简单的分支,再处理较复杂的分支。对多分支的情况,也可遵循“由易到难”的原则。因为简单的分支只需要较少的指令就能处理完,一旦处理完这种情况后,在后面的编程过程中就可集中考虑如何处理复杂的分支。 (a) if endif结构(b) ifelseendif结构图6.2 分支结构的二种结构例6.5 已知字

18、节变量CHAR1,编写一程序段,把它由小写字母变成大写字母。解:DATA1SEGMENTCHAR1DB?DATA1ENDSCODE1SEGMENTMOVAL, CHAR1CMPAL, aJBnextCMPAL, zJAnextSUBCHAR1, 20H;指令AND CHAR1, 0DFH也可以next:CODE1ENDS例6.6 编写一程序段,计算下列函数值。其中:变量X和Y是有符号字变量。解:DATA1SEGMENTXDW?YDW?DATA1ENDSCODE1SEGMENTMOVAX, XCMPAX, 0JGEcase23ADDAX, 10;第一种情况的计算结果JMPresultcase23

19、:CMPAX, 10DJGcase3MOVBX, 30DIMULBX;第二种情况的计算结果JMPresultcase3:SUBAX, 9;第三种情况的计算结果result:MOVY, AX;把计算结果保存到变量Y中CODE1ENDS例6.7 把下列C语言的语句改写成等价的汇编语言程序段(不考虑运算过程中的溢出)。If (a+b 0 & c%2 = 0) a = 62;else a = 21;其中:变量a,b和c都是有符号的整型(int)变量。解:DATA1SEGMENTADW?BDW?CDW?DATA1ENDSCODE1SEGMENTMOVAX, AADDAX, BJLE_ELSE;ADD指令

20、会改变算术标志位 TESTC, 1;C%2=0,也就是:看C的最低位是否为0JNZ_ELSEMOVA, 62DJMPNEXT_ELSE:MOVA, 21DNEXT:CODE1ENDS例6.8 用地址转移表实现下列C语言的switch语句,其中:变量A和B是有符号的整型(int)变量。switch(a%8)case 0:b = 32;break;case 1:case 2:b = a + 43;break;case 3:b = 2*a;break;case 4:b-;break;case 5:case 6:case 7:printf(“Function 5_6_7”);break;解:DATA1

21、SEGMENTADW?BDW?TableDWcase0. case12, case12, case3DWcase4, case567, case567, case567MSGDBFunction 5_6_7$DATA1ENDSCODE1SEGMENTMOVAX, AMOVBX, AXANDBX, 7;得到BX的低三位,实现a%8的计算SHLBX, 1;由于地址表是字类型,其下标要乘2JMPTableBX;利用地址表实现多路转移case0:MOVB, 32DJMPnextcase12:ADDAX, 43DMOVB, AXJMPnextcase3:SHLAX, 1MOVB, AXJMPnextca

22、se4:DECBJMPnextcase567:LEADX, MSGMOVAH, 9INT21HJMPnextnext:CODE1ENDS用地址表实现多路转移的关键在于:转移入口的地址表和转移情况可整数化。如果这二个要求有一个不满足,或很难构造,则无法使用该方法。为了改善汇编语言源程序的结构,减少显式转移语句所带来混乱,在宏汇编MASM 6.11系统中,增加了表达分支结构的伪指令。该伪指令的书写格式与高级语言的书写方式相类似,汇编程序在汇编时会自动增加转移指令和相应的标号。理解并掌握该知识,对将来学习编译原理课程也有一定的帮助。分支伪指令的具体格式如下:格式1:.IF condition;以英文

23、“句号”开头 指令序列 ;条件condition成立时所执行的指令序列.ENDIF格式2:.IF condition 指令序列1.ELSE 指令序列2;条件condition不成立时所执行的指令序列.ENDIF格式3:.IF condition1 指令序列1.ELSEIF condition2 指令序列2;条件condition2成立时所执行的指令序列.ENDIF其中:条件表达式“condition”的书写方式与C语言中条件表达式的书写方式相似,也可用括号来组成复杂的条件表达式。条件表达式中可用的操作符有:=(等于)、!=(不等)、(大于)、=(大于等于)、(小于)、=a & AL=z;语句象

24、C语言语句吗?SUBCHAR1, 20H.ENDIF也可把例6.6的代码段部分就可写成如下程序段:MOV AX, X.IFAX 0ADDAX, 10;计算第一种情况的结果.ELSEIFAX = 10MOVBX, 30DIMULBX;计算第二种情况的结果.ELSESUBAX, 9;计算第三种情况的结果.ENDIFMOVY, AX;把计算结果保存到变量Y中例6.9 根据当前计算机的时间和日期,显示上午(AM)或下午(PM),以及所在的季节。解:显示解答6.2.3 循环结构循环结构是一个重要的程序结构,它具有重复执行某段程序的功能。通常,循环结构包括以下四个组成部分:1、循环初始化部分初始化循环控制

25、变量、循环体所用到变量;2、循环体部分循环结构的主体;3、循环调整部分循环控制变量的修改、或循环终止条件的检查;4、循环控制部分程序执行的控制转移。以上四部分可以在程序中用各种不同的形式体现出来,有时也并非清析地表达出来。常用的循环结构如图6.3所示。(a)、DoWhile结构(b)、While结构图6.3 常用的循环结构示意图一、用循环指令构成循环结构在编写循环结构的程序片段时,我们可以多种方法来循环结构。如:循环次数是已知的,可用LOOP指令来构造循环;当循环次数是未知或不定的,则可用条件转移或无条件转移来构成循环结构。例6.10 分类统计字数组data中正数、负数和零的个数,并分别存入内

26、存字变量Positive、Negative和Zero中,数组元素个数保存在其第一个字中。解:显示解答例6.11 计算数组score的平均整数,并存入内存字变量Average中,数组以-1为结束标志。解:DATA1SEGMENTdataDW90, 95, 54, 65, 36, 78, 66, 0, 99, 50, -1AverageDW0DATA1ENDSCODE1SEGMENTASSUMECS:CODE1, DS:DATA1START:MOVAX, DATA1MOVDS, AXXORAX, AXXORDX, DX;用(DX,AX)来保存数组元素之和XORCX, CX;用CX来保存数组元素个数LEASI, data;用指针SI来访问整个数组again:MOVBX, word ptr SICMP

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1