STACK
SEGMENT
DW 100 DUP (?)
TOS LABEL WORD STACK ENDS ;以上定义堆栈段 ;****************************************** CSEG SEGMENT TELIST PROC FAR ;主程序TELIST
ASSUME CS: CSEG, DS: DSEG, ES: DSEG, SS: STACK
START: MOV AX, STACK
MOV SS, AX ;给SS赋值 MOV SP, OFFSET TOS ;给SP赋值 PUSH DS ;设置返回DOS SUB AX, AX PUSH AX MOV AX, DSEG MOV DS, AX ;给DS赋值 MOV ES, AX ;给ES赋值
BEGIN: LEA DX, MESG1
MOV AH, 09H ;显示字符串功能调用 INT 21H CALL INPUT_NAME ;输入姓名 LEA DX, MESG2 MOV AH, 09H ;显示字符串功能调用 INT 21H CALL INPHONE ;输入电话号码 CALL PRINTLINE ;显示姓名及电话号码 RET
TELIST ENDP
;-------------------------------------------------------------------------- INPUT_NAME PROC NEAR ;输入姓名子程序
CALL GETCHAR ;调输入字符子程序输入姓名 LEA SI, INBUF ;把INBUF中的姓名移入输出行OUTNAME LEA DI, OUTNAME MOV CX, 12 CLD REP MOVSB RET
INPUT_NAME ENDP ;INPUT_NAME子程序结束
;-------------------------------------------------------------------------- INPHONE PROC NEAR ;输入电话号码子程序
CALL GETCHAR ;调输入字符子程序输入电话号码 LEA SI, INBUF ;把INBUF中的电话号码移入输出行OUTPHONE LEA DI, OUTPHONE MOV CX, 12 CLD REP MOVSB RET
INPHONE ENDP ;INPHONE子程序结束
;-------------------------------------------------------------------------- GETCHAR PROC NEAR ;键盘输入子程序
MOV AL, 20H ;先将INBUF中填满空格字符 MOV CX, 12 LEA DI, INBUF CLD REP STOSB
46
MOV CX, 12 ;向INBUF输入字符 MOV DI, 0
INPUT: MOV AH, 1 ;从键盘接收一个字符并回显的DOS功能调用
INT 21H CMP AL, 0DH ;输入回车符返回 JZ QUIT
MOV INBUF[DI], AL INC DI LOOP INPUT
QUIT: CALL DISP_CRLF
RET
GETCHAR ENDP ;GETCHAR子程序结束
;-------------------------------------------------------------------------- PRINTLINE PROC NEAR ;显示姓名及电话号码子程序
LEA DX, MESG3 MOV AH, 09H ;显示字符串功能调用 INT 21H LEA DX, OUTNAME ;显示姓名及电话号码 MOV AH, 09H ;显示字符串功能调用 INT 21H RET
PRINTLINE ENDP ;PRINTLINE子程序结束
;-------------------------------------------------------------------------- DISP_CRLF PROC NEAR ;显示回车换行符子程序
LEA DX, CRLF MOV AH, 09H INT 21H RET
DISP_CRLF ENDP ;DISP_CRLF子程序结束
;-------------------------------------------------------------------------- CSEG ENDS ;以上定义代码段 ;******************************************
END START
6.10 编写子程序嵌套结构的程序,把整数分别用二进制和八进制形式显示出来。
主程序BANDO:把整数字变量VAL1存入堆栈,并调用子程序PAIRS;
子程序PAIRS:从堆栈中取出VAL1;调用二进制显示程序OUTBIN显示出与其等效的二进制数;输出8
个空格;调用八进制显示程序OUTOCT显示出与其等效的八进制数;调用输出回车及换行符子程序。
答:程序如下:
DSEG SEGMENT VAL1 DW ? CRLF DB 0DH, 0AH, ‘$’ DSEG ENDS ;以上定义数据段 ;****************************************** CSEG SEGMENT BANDO PROC FAR ;主程序BANDO
ASSUME CS: CSEG, DS: DSEG
START: PUSH DS ;设置返回DOS
SUB AX, AX PUSH AX MOV AX, DSEG MOV DS, AX ;给DS赋值
PUSH VAL1 CALL PAIRS
47
RET
BANDO ENDP
;-------------------------------------------------------------------------- PAIRS PROC NEAR ;PAIRS子程序
PUSH BP MOV BP, SP PUSH BX
MOV BX, [BP+4] ;从堆栈中取出VAL1 CALL OUTBIN ;调用二进制显示子程序 MOV CX, 8 ;显示8个空格符
SPACE: MOV DL, ‘ ’
MOV AH, 2 INT 21H LOOP SPACE CALL OUTOCT ;调用八进制显示子程序 CALL DISP_CRLF POP BX POP BP RET 2
PAIRS ENDP ;PAIRS子程序结束
;-------------------------------------------------------------------------- OUTBIN PROC NEAR ;二进制显示子程序
PUSH BX MOV CX, 16
ONEBIT: ROL BX, 1
MOV DX, BX AND DX, 1 OR DL, 30H ;转换为ASCII码 MOV AH, 2 INT 21H LOOP ONEBIT POP BX RET
OUTBIN ENDP ;OUTBIN子程序结束
;-------------------------------------------------------------------------- OUTOCT PROC NEAR ;八进制显示子程序
ROL BX, 1 ;16位二进制数包含6位八进制数,最高位仅1位 MOV DX, BX AND DX, 1 OR DL, 30H ;转换为ASCII码 MOV AH, 2 INT 21H MOV CX, 5 ;余下还有5位八进制数
NEXT: PUSH CX
MOV CL, 3 ;1位八进制数包含3位二进制数 ROL BX, CL MOV DX, BX AND DX, 07H OR DL, 30H ;转换为ASCII码 MOV AH, 2 INT 21H POP CX LOOP NEXT RET
OUTOCT ENDP ;OUTOCT子程序结束
;--------------------------------------------------------------------------
48
DISP_CRLF PROC NEAR ;显示回车换行符子程序
LEA DX, CRLF MOV AH, 09H INT 21H RET
DISP_CRLF ENDP ;DISP_CRLF子程序结束
;-------------------------------------------------------------------------- CSEG ENDS ;以上定义代码段 ;******************************************
END START
6.11 假定一个名为MAINPRO的程序要调用子程序SUBPRO,试问:
(1) MAINPRO中的什么指令告诉汇编程序SUBPRO是在外部定义的? (2) SUBPRO怎么知道MAINPRO要调用它? 答:(1) EXTRN SUBPRO:FAR
(2) PUBLIC SUBPRO
6.12 假定程序MAINPRO和SUBPRO不在同一模块中,MAINPRO中定义字节变量QTY和字变量VALUE和PRICE。
SUBPRO程序要把VALUE除以QTY,并把商存在PRICE中。试问: (1) MAINPRO怎么告诉汇编程序外部子程序要调用这三个变量?
(2) SUBPRO怎么告诉汇编程序这三个变量是在另一个汇编语言程序定义的? 答:(1) PUBLIC QTY, VALUE, PRICE
(2) EXTRN QTY:BYTE, VALUE:WORD, PRICE:WORD 6.13 假设:
(1) 在模块1中定义了双字变量VAR1,首地址为VAR2的字节数据和NEAR标号LAB1,它们将由模块2
和模块3所使用;
(2) 在模块2中定义了字变量VAR3和FAR标号LAB2,而模块1中要用到VAR3,模块3中要用到LAB2; (3) 在模块3中定义了FAR标号LAB3,而模块2中要用到它。 试对每个源模块给出必要的EXTRN和PUBLIC说明。 答:模块1:
EXTRN VAR3: WORD
PUBLIC VAR1,VAR2,LAB1
模块2:
EXTRN VAR1: DWORD,VAR2: BYTE,LAB1: NEAR,LAB3: FAR PUBLIC VAR3,LAB2
模块3:
EXTRN VAR1: DWORD,VAR2: BYTE,LAB1: NEAR,LAB2: FAR PUBLIC LAB3 6.14 主程序CALLMUL定义堆栈段、数据段和代码段,并把段寄存器初始化,数据段中定义变量QTY和PRICE;
代码段中将PRICE装入AX,QTY装入BX,然后调用子程序SUBMUL。程序SUBMUL没有定义任何数据,它只简单地把AX中的内容(PRICE)乘以BX中的内容(QTY),乘积放在DX: AX中。请编制这两个要连接起来的程序。 答:程序如下:
TITLE CALLMUL ;主程序 EXTRN SUBMUL: FAR
;----------------------------------------------------------------- STACK SEGMENT PARA STACK ‘STACK’
DW 64 DUP (?)
TOS LABEL WORD STACK ENDS
;-------------------------------------------------------------- DATASG SEGMENT PARA ‘DATA’ QTY DW 0140H PRICE DW 2500H DATASG ENDS
;--------------------------------------------------------------
49
CODESG SEGMENT PARA ‘CODE’ CALLMUL PROC FAR
ASSUME CS: CODESG, DS: DATASG, SS: STACK
START: MOV AX, STACK
MOV SS, AX ;给SS赋值 MOV SP, OFFSET TOS ;给SP赋值 PUSH DS SUB AX, AX POP AX MOV AX, DATASG MOV DS, AX
MOV AX, PRICE MOV BX, QTY CALL SUBMUL RET
CALLMUL ENDP CODESG ENDS
;-----------------------------------------------------------------
END CALLMUL
;*************************************************************** TITLE SUBMUL ;子程序 PUBLIC SUBMUL
;----------------------------------------------------------------- CODESG1 SEGMENT PARA ‘CODE’
ASSUME CS: CODESG1
SUBMUL PROC FAR
ASSUME CS: CODESG1 MUL BX RET
SUBMUL ENDP CODESG1 ENDS
;-----------------------------------------------------------------
END
6.15 试编写一个执行以下计算的子程序COMPUTE:
R ← X + Y - 3
其中X,Y及R均为字数组。假设COMPUTE与其调用程序都在同一代码段中,数据段D_SEG中包含X和Y数组,数据段E_SEG中包含R数组,同时写出主程序调用COMPUTE过程的部分。
如果主程序和COMPUTE在同一程序模块中,但不在同一代码段中,程序应如何修改? 如果主程序和COMPUTE不在同一程序模块中,程序应如何修改? 答:(1) 主程序和COMPUTE在同一代码段中的程序如下:
TITLE ADDITION ;主程序
;-------------------------------------------------------------- D_SEG SEGMENT PARA ‘DATA’ COUNT EQU 10H X DW COUNT DUP (?) Y DW COUNT DUP (?) D_SEG ENDS
;-------------------------------------------------------------- E_SEG SEGMENT PARA ‘DATA’ R DW COUNT DUP (?) E_SEG ENDS
;-------------------------------------------------------------- C_SEG SEGMENT PARA ‘CODE’ ADDITION PROC FAR
50