第四章.汇编语言程序设计
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的功能号,不在考察范围内,就不想写了,参考它的格式很容易写出来。