第四章.汇编语言程序设计
1.源程序的基本结构
.486
DATA SEGMENT USE16 ;定义数据段
MESG DB 'HELLO',0DH,0AH,'$'
DATA ENDS
CODE SEGMENT USE16 ;定义代码段
ASSUME CS:CODE,DS:DATA
BGE: MOV AX,DATA ;这个是入口语句,这里必须定义一个名字
MOV DS,AX ;传送类指令MOV不能直接传送两个段
MOV CX 10
LAST:MOV AH 9
MOV DX OFFSET MESG
INT 21H
LOOP LAST
MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END BGE ;汇编结束
说明:
ASSUME语句是段约定,我们通常把ASSUME语句作为代码段的第一条语句。ASSUME语句只是规定了某个逻辑段进行寻址操作时选用哪一个段寄存器,而段寄存器的初值必须在程序中用指令设置。
2.汇编语言的编程格式分为2种,EXE文件格式和COM文件格式。
(1)COM文件格式
COM文件格式适合编译较小的程序。它必须满足:
汇编语言只能使用一个逻辑段(代码段),不能使用堆栈段。
代码段的偏移地址为100H的单元
代码段小于64K(偏移地址为100H,用户程序64K-256)
.486
CODE SEGMENT USE16
ASSUME CS:CODE
ORG 100H ;偏移地址设置为100H,这个是COM文件格式的规定
BEG: JMP START
MESG DB 'HELLO','0DH','0AH','$' ;用户程序数据区,0DH回车,0AH换行
START: MOV CX,10
LAST: MOV AH,9
MOV DX,0FFSET MESG
INT 21H ;利用DOS功能调用09H,显示字符串HELLO
LOOP LAST
MOV AH,4CH
INT 21H ;返回DOS
CODE ENDS
END BEG
本程序只有一个以CODE为短名的代码段,用户程序使用的数据放在程序之前。用OGE伪指令,在偏移地址为100H的地方放置一条JMP START指令跳过数据区。
COM文件返回DOS,可以直接调用INT 20H
(2)EXE文件格式
每个逻辑块的大小不超过64K
3.返回DOS的方法:
(1)通过调用21H
MOV AH,4CH
INT 21H
(2)通过调用20H
在EXE文件格式下,可以调用PSP首单元的INT20H指令返回DOS。
.486
DATA SEGMENT USE16
MESG DB 'HELLO','0AH','0DH','$'
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA,SS:STACK ;说明段约定
MAIN PROC FAR ;思考为什么这里要定义FAR,学习子程序怎么写
BEG: PUSH DS ;入口程序
MOV AX,0
PUSH AX
MOV AX,DATA
MOV DS,AX
LAST:MOV AH,9
MOV DX,0FFSET MESG
INT 21H
RET
MAIN ENDP ;注意这里是ENDP,子程序的结束
CODE ENDS
END BEG
思考:
1.为什么这里需要定义子程序以及为什么指定为far。
首先,我们知道EXE文件的内存映像,CS:IP指向代码段的首地址,我们如果想借助INT 20H返回DOS系统,那么在代码段执行结束后必须让CS:IP指向PSP段(段前缀,范围是0-100H)的开头,也就是INT20H。
其次,如果我们指定子程序返回属性是FAR,那么子程序结束后,就会从栈顶POP出4个字节,并且赋值给CS:IP,我们只需要在先前将PSP字段的首地址(DS:0000H)压入堆栈,即可实现该功能。如果不加说明为FAR,那么一般默认是NEAR,那么只会POP出2个字节,没办法对CS:IP正确赋值。
2.熟悉一下子程序的定义结构
名字 PROC 属性
子程序体
RET
名字 ENDP
属性可以指定是FAR NEAR。。。。缺省为NEAR
3.思考为什么字符串最后有个$
应为这里调用的是DOS的09H功能显示一个字符串,而09H要求字符串必须以$作为结束符
3.在屏幕上显示’I AM A STUDENT!’,要求使用9号的DOS功能
.486
DATA SEGMENT USE16 ;定义数据段
MSG DB 'I am a student!','$'
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA
BEG: MOV AX,SEG DATA
MOV DS,AX
MOV DX,OFFSET MESG
MOV AH,9
INT 21H
MOV AH,4CH
INT 21H
CODE ENDS
END BEG
4.设计一个人机对话程序,如下:(要求使用DOS系统功能调用1,2,9,0A)
what is your name? LI LEI
LI LEI?(Y/N) N
what is your name? LI MEI
LI MEI?(Y/N) Y
.486
DATA SEGMENT USE16
MSG1 DB ODH,OAH ;分别为回车和换行,回车是回到一行开始的地方,换行是到下一行
DB 'What is your name?$'
MSG2 DB '?(Y/N)$'
BUF DB 30 ;最大为30个单元
DB ? ;实际单元个数
DB 30 DUP(?)
DATA ENDS
CODE SEGMENT USE16
ASSUME DS:DATA,CS:CODE
BEG: MOV AX,SEG DATA
MOV DS,AX
AGAIN: MOV AH 9
MOV DX,OFFSET MSG1
INT 21H ;询问姓名
MOV AH,0AH ;等待键入一个字符串
MOV DX,OFFSET BUF
INT 21H ;接受一个键入的字符串
MOV BL,BUF+1 ;键入字符串的实际长度,存到BX中
MOV BH,0
MOV SI,OFFSET BUF+2
MOV BYTE PTR[BX+SI],'$' ;在字符串末尾加上$符,应为后面需要用09H显示字符串
MOV AH,2
MOV DL,0AH ;光标下移一行
INT 21H
MOV AH,9
MOV DX,OFFSET BUF+2
INT 21H ;复制键入的字符串
MOV AH,9
MOV DX,OFFSET MSG2
INT 21H ;显示确定消息
MOV AH,1
INT 21H ;等待键入一个字符串
CMP AL,'Y' ;和Y比较
JNE AGAIN ;不相等表示输入的是N,不相同重新输入
MOV AH,4CH
INT 21H
CODE ENDS
END BEG
5.显示I AM A STUDENT,红底白字,用BIOS文本显示功能。
显示HELLO,黑底灰白字符,用DOS功能。
.486
DATA SEGMENT USE16
MESG1 DB 'HELLO!'
MESG2 DB 'I AM A STUDENT.'
LL =$-MESG2 ;计算出长度
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA,ES:DATA
BEG:MOV AX,DATA
MOV DS,AX
MOV ES,AX
MOV AX,0003H ;一举两得,设置了AH=00H,AL=03H,执行了BIOS文本显示的00功能,AL设置了显示方式
INT 10H
MOV AH,9
MOV DX,OFFSET MESG1
INT 21H
CODE ENDS
END BEG
由于BIOS文本显示13H的功能号,不在考察范围内,就不想写了,参考它的格式很容易写出来。