汇编第五次(子程序设计)实验(设计性实验)
一、实验要求和目的
1.熟悉汇编语言程序设计结构;
2.熟悉汇编语言子程序设计方法;
3.熟悉利用汇编语言子程序参数传递方法;
4.熟悉汇编语言字符串处理基本指令的使用方法;
5.掌握利用汇编语言实现字符串的输入输出程序设计方法;
6.掌握数制转换程序实现方法。
二、软硬件环境
1、硬件环境:计算机系统 windows;
2、软件环境:装有MASM、DEBUG、LINK、等应用程序。
三、实验涉及的主要知识
A) 子程序知识要点:
1.掌握子程序的定义语句
过程名 PROC [near/far]
过程体
RET
过程名 ENDP
2.子程序结构形式
一个完整的子程序一般应包含下列内容:
1)子程序的说明部分
在设计了程序时,要建立子程序的文档说明,使用户能清楚此子程序的功能和调用方法。
说明时,应含如下内容:
子程序名:命名时要名中见意;
子程序的功能:说明子程序完成的任务;
子程序入口参数:说明子程序运行所需参数及存放位置;
子程序出口参数:说明子程序运行结果的参数及存放位置;
子程序所占用的寄存器和工作单元;
子程序调用示例;
2)掌握子程序的调用与返回
在汇编语言中,子程序的调用用CALL,返回用RET指令来完成。
段内调用与返回:调用子程序指令与子程序同在一个段内,因此只修改IP;
段间调用与返回:调用子程序与子程序分别在不同的段,因此在返回时,需同时修改
CS:IP。
3)子程序的现场保护与恢复
保护现场:在子程序设计时,CPU内部寄存器内容的保护和恢复。
一般利用堆栈实现现场保护和恢复的格式:
过程名 PROC [NEAR/FAR]
PUSH AX
PUSH BX
PUSH DX
POP DX
POP AX
RET
过程名 ENDP
3.子程序的参数传递方法
1.寄存器传递参数
这种方式是最基本的参数传递方式。
2.存储器单元传(变量)递参数
这种方法是在主程序调用子程序前,将入口参数存放到约定的存储单元中;子程序运
行时到约定存储位置读取参数;子程序执行结束后将结果也放在约定存储单元中。
3.用堆栈传递参数
利用共享堆栈区来传递参数是重要的的方法之一。
B) 字符、字符串输入输出知识要点:
在实际应用中,经常需要从键盘输入数据并将结果等内容显示到屏幕上,方便程序控制
及查看结果。汇编语言的数据输入和输出分成两类,一是单个字符数据的输入输出,一是字
符串数据的输入输出,都可以通过DOS功能调用来实现,下面就分别介绍下用来实现数据输
入输出的功能调用的使用方法。
1.单个字符输入
单个字符输入可以利用DOS的1号功能调用来完成,使用方法为:
MOV AH,1
INT 21H
这两条语句执行后,光标会在屏幕上闪烁,等待输入数据,输入的数据以ASCII码形式存储在AL寄存器中。
2.单个字符输出
单个字符输出可利用DOS2号功能调用来完成,使用方法为:
MOV DL,’?’
MOV AH,2
INT 21H
单个字符输出需要把要输出字符的ASCII码放在DL寄存器中。
3.字符串输入
从键盘输入一串字符串可以利用DOS的10号功能调用来完成,使用方法为:
BUF DB 50 ;预定义可以输入的最大字符个数
DB ? ;实际输入字符个数,根据输入自动统计
DB 50 DUP (?) ;存放输入字符串数据缓冲区
LEA DX,BUF
MOV AH,10
INT 21H
4.字符串输出
字符串输出可由DOS9号功能调用来完成,使用方法为:
STRING DB ‘HELLO$’
LEA DX,STRING
MOV AH,9
INT 21H
C) 表的处理知识要点:
表的处理在实际数据处理中应用较为广泛,主要有排序、搜索、插入和删除等操作。有一些常用的冒泡法、对分搜索法等需要掌握。
四、实验内容与步骤
1.从键盘输入一串字符串(显示提示)到内存中,在该字符串的某一个指定位置,插入某一字符或删除某一字符,并显示操作后的字符串。
1)代码
DATA SEGMENT
BUF DB 25
ACTHAR DB ?
CHAR DB 25 DUP (?)
DB '$'
STR DB '1.INSERT 2.DELETE', '$'
STR1 DB 'PLEASE INPUT:', '$'
STR2 DB 0DH, 0AH, '$'
PLACE DB ?
CHR DB ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET STR1
MOV AH, 09H
INT 21H
MOV DX, OFFSET BUF
MOV AH, 0AH
INT 21H
MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
MOV DX, OFFSET STR
MOV AH, 09H
INT 21H
MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
MOV AH, 1
INT 21H
MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
CMP AL, 31H
JNZ DELETE
CALL INSERT
JMP L
DELETE:CALL DELE
L: MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
MOV DX, OFFSET CHAR
MOV AH, 09H
INT 21H
MOV AH, 4CH
INT 21H
INSERT PROC NEAR
MOV DX, OFFSET STR1
MOV AH, 09H
INT 21H
MOV AH, 01H
INT 21H
SUB AL, 30H
MOV PLACE, AL
MOV AH, 01H
INT 21H
MOV CHR, AL
MOV CX, 0000H
MOV CL, [ACTHAR]
MOV SI, CX
MOV BX, OFFSET CHAR
MOV AL, '$'
MOV [BX][SI], AL
SUB CL, PLACE
INC CX
INC CX
L1: MOV AL, CHAR[SI]
MOV CHAR[SI+1], AL
DEC SI
LOOP L1
INC SI
MOV AL, CHR
MOV CHAR[SI], AL
RET
INSERT ENDP
DELE PROC NEAR
MOV DX, OFFSET STR1
MOV AH, 09H
INT 21H
MOV AH, 01H
INT 21H
SUB AL, 30H
MOV PLACE, AL
MOV SI, WORD PTR PLACE
MOV CX, 0
MOV CL, ACTHAR
MOV DI, CX
MOV AL, '$'
MOV [CHAR][DI], AL
INC CX
SUB CL, PLACE
L2: MOV AL, CHAR[SI]
MOV CHAR[SI-1], AL
INC SI
LOOP L2
RET
DELE ENDP
CODE ENDS
END START
2)操作步骤
实例1:-g使程序运行,输入字符串‘segmentdebug’,选择插入字符,在第8个字符处插入‘!’。
程序运行的结果如下:
实例2:-g使程序运行,输入字符创‘segment!Debug’,选择删除字符,删除第8个字符。
程序运行结果如下:
2、编写程序把从键盘输入的四位十六进制数,转换为十进制形式在屏幕上打印出来。
1)代码
DATA SEGMENT
NUM10 DB 5 DUP (?)
NUM DB 6 DUP (?)
INPUT DB 5
ACTUAL DB ?
CHAR DB 5 DUP (?)
DB '$'
NUM16 DW ?
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START: MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET INPUT
MOV AH, 0AH
INT 21H
CALL FUNC
CALL PRINT
MOV AH, 4CH
INT 21H
FUNC PROC NEAR
MOV CX, 4
MOV AX, 0
MOV DX, 0
MOV SI, 0
MOV BX, 0
L1: MOV BX, 10H
MUL BX
MOV BL, CHAR[SI]
CMP BX, 41H
JS G1
SUB BL, 37H
JMP G2
G1: SUB BL, 30H
G2: ADD AX, BX
INC SI
LOOP L1
MOV NUM16, AX
RET
FUNC ENDP
PRINT PROC NEAR
MOV AX, NUM16
MOV DX, 0
MOV SI, 0
MOV BX, 0AH
L2: CMP AX, 0
JZ S
IDIV BX
MOV NUM10[SI], DL
MOV DX, 0
INC SI
JMP L2
S: MOV CX, SI
MOV DI, 0
S1: DEC SI
MOV AL, NUM10[SI]
ADD AL, 30H
MOV NUM[DI], AL
INC DI
LOOP S1
MOV AL, '$'
MOV NUM[DI], AL
MOV DX, OFFSET NUM
MOV AH, 09H
INT 21H
RET
PRINT ENDP
CODE ENDS
END START
2)操作步骤
运行程序。输入十六进制数8B9AH,十进制为35738
程序运行结果如下,结果正确。
3、从键盘输入(显示提示)十个2位十进制数(正数)到内存中,按从小到大排序,然后把该数以十六进制形式在屏幕上打印出来。
1)代码
DATA SEGMENT
NUMD DB 3
ACTUAL DB ?
CHAR DB 3 DUP (?)
DB '$'
NUMX DB 10 DUP (?)
DB '$'
PRINT DB 2 DUP (?)
DB '$'
STR1 DB 'PLEASE INPUT:', '$'
STR2 DB 0DH, 0AH, '$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
START:
MOV AX, DATA
MOV DS, AX
CALL INPUT
CALL OUTPUT
MOV AH, 4CH
INT 21H
INPUT PROC NEAR
MOV CX, 10
MOV SI, 0
L1: MOV DX, OFFSET STR1
MOV AH, 09H
INT 21H
MOV DX, OFFSET NUMD
MOV AH, 0AH
INT 21H
MOV AX, 0
MOV BX, 0AH
MOV AL, [CHAR]
SUB AL, 30H
MUL BL
MOV BL, 1[CHAR]
SUB BL, 30H
ADD AL, BL
MOV NUMX[SI], AL
INC SI
MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
LOOP L1
RET
INPUT ENDP
OUTPUT PROC NEAR
MOV CX, 10
L2: MOV SI, 0
MOV BX, CX
SUB BX, 1
K: CMP SI, BX
JZ S
MOV AL, NUMX[SI]
MOV AH, NUMX[SI+1]
CMP AL, AH
JNS M
JMP N
M: XCHG AL, AH
MOV NUMX[SI], AL
MOV NUMX[SI+1], AH
N: INC SI
JMP K
S: LOOP L2
MOV SI, 0
MOV CX, 10
MOV BX, 10H
L3: MOV AX, 0
MOV AL, NUMX[SI]
DIV BL
CMP AL, 0AH
JS M1
ADD AL, 37H
JMP M2
M1: ADD AL, 30H
M2: MOV PRINT, AL
CMP AH, 0AH
JS M3
ADD AH, 37H
JMP M4
M3: ADD AH, 30H
M4: MOV PRINT[1], AH
MOV DX, OFFSET PRINT
MOV AH, 09H
INT 21H
MOV DX, OFFSET STR2
MOV AH, 09H
INT 21H
INC SI
LOOP L3
RET
OUTPUT ENDP
CODE ENDS
END START
2)操作步骤
运行程序。输入十个十进制数:99、98、97、30、45、87、63、46、56、38。
程序运行结果如下,输出的十六进制数为:1EH、26H、2DH、2EH、38、3FH、57H、61H、62H、63H。结果正确。
五、思考与练习
1.字符串在内存中是如何存储的?
字符串在内存中以字节(byte)为单位存储,字符串包含多少字符就需要多少byte来存。汇编中定义一个字符串如下:
myString BYTE "ABCDEF",0 ;常以0作为字符串的结尾
内存中存储顺序如图所示,从箭头开始,依次向下。假设第一个地址是0000h,下一个byte的地址就是00001h,依次类推。内存中存储的是字符的二进制编码,比如A 41h=0100 0001b。
2.屏幕有多个字符串显示时,如何换行?
在内存中定义一个字符串为:“STR2 DB 0DH, 0AH, '$'”,当需要换行的时候,输出这个字符串就可以了。
第二篇:北京理工大学汇编语言实验报告4分支和循环程序设计实验(设计性实验)
实验四 分支和循环程序设计实验(设计性实验)
一、实验要求和目的
1.熟悉汇编语言程序设计结构;
2.熟悉汇编语言分支程序基本指令的使用方法;
3.掌握利用汇编语言实现单分支、双分支、多分支的程序设计方法;
4.了解汇编语言循环程序设计的基本流程;
5.熟悉汇编语言循环基本指令的使用方法;
6.掌握利用汇编语言的循环指令完成循环程序设计方法。。
二、软硬件环境
1、硬件环境:计算机系统 windows;
2、软件环境:装有MASM、DEBUG、LINK、等应用程序。
三、实验涉及的主要知识
在实际应用中,经常根据一些条件来选择一条分支执行。汇编语言的条件判断主要是通
过状态寄存器中的状态位、无符号数相减或有符号相减而导致的结果来进行。
1.无条件转移指令JMP
无条件转移指令JMP 是使程序无条件转移至目标处,又分为段内转移、段间转移。
2.条件转移指令JXX
条件转移指令可分为三大类:
1).简单条件转移指令指令。根据单个标志位的状态判断转移条件。
标志位 指令 转移条件 意义
JC CF=1 有进位/借位
CF
JNC CF=0 无进位/借位
JE/JZ ZF=1 相等/等于0
ZF
JNE/JNZ ZF=0 不相等/不等于0
JS SF=1 是负数
SF
JNS SF=0 是正数
JO OF=1 有溢出
OF
JNO OF=0 无溢出
JP/JPE PF=1 有偶数个1
PF
JNP/JPO PF=0 有奇数个1
2).无符号数条件转移指令。
假设在条件转移指令前使用比较指令,比较两个无符号数A,B,指令进行的的操作是
A-B,其转移指令如下:
指令 转移条件 意义
JA/JNBE CF=0 AND ZF=0 A>B
JAE/JNB CF=0 OR ZF=1 A>=B
JB/JNAE CF=1 AND ZF=0 A<B
JBE/JNA CF=1 OR ZF=1 A<=B
3).带符号数条件转移指令。
指令 转移条件 意义
JG/JNLE SF=OF AND ZF=0 A>B
JGE/JNL SF=OF OR ZF=1 A>=B
JL/JNGE SF OF AND ZF=0 A<B
JLE/JNG SF OF OR ZF=1 A<=B
在汇编程序设计中,要熟练使用循环指令和跳转等指令来实现循环,理解循环体结构中
的初始化部分、循环体、结束部分,并且要结合前面分支结构相关的知识点,加深对循环结
构的理解和掌握。循环结构的组成及其设计方法的知识要点有:
1、循环程序的基本结构通常由3 部分组成
1) 初始化部分
建立循环初始值,为循环做准备,如设置地址指针,(BX/SI/DI/BP),初始化循环控制变量
或计数器(CX),数据寄存器(AX/DX)初值等.
2) 循环体
循环体是循环程序的主体,是程序中重复执行的程序段.它是由循环工作部分、修改部
分、和循环控制部分。
①循环工作部分:完成程序功能的主要程序段,用于解决程序的实际任务;
②修改部分:对循环参数进行修改,并为下一次循环做准备;
③循环控制部分:判断循环结束条件是否满足。通常判断循环结束方法:
用计数控制循环;循环是否进行了预定的次数。
用条件控制循环。循环终止条件是否满足。
3)结束处理处理部分
主要是对循环的结果进行处理,比如现实提示信息等,很多时候没有此部分程序。
2、循环控制指令:
指令格式 执行操作 循环结束条件
LOOP 标号 CX=CX-1; 若CX=0,则循环 CX=0
LOOPNZ/LOOPNE 标号 CX=CX-1; 若CX=0 且ZF=0,则循环 CX=0 或ZF=0
LOOPZ/LOOPE 标号 CX=CX-1; 若CX=0 且ZF=1,则循环 CX=0 或ZF=1
JCXZ 标号 仅测试(CX)=0? 若等于0,则转移到目标地址,否则就顺序执行
3、循环控制可以分为:计数循环和条件循环。作为计数循环,一般是指循环次数是已
知的情况,在程序设计的的循环时,先应将循环次数送入计数器CX 中进行计数,在循环体
中使用LOOP 等循环指令。当然,也可以通过其他方式来进行,如cx←cx-1,jnz 等结合实
现。
四、实验内容与步骤
1、判断方程AX2+BX+C=0 是否有实根。若有实根,则将字节变量tag 置1,否则置0。假
设A、B、C 均为字节变量,数据范围为-128~127。
·源代码如下:
DATAS SEGMENT
a dw 2
b dw 8
d dw 5
tag db ?;此处输入数据段代码
DATAS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov cx,b
mov ax,0
l1: add ax,b
loop l1
mov cx,d
mov dx,0
l2:add dx,a
loop l2
mov cx,4
add bx,dx
cmp ax,bx
jge exist
mov tag,0
jmp done
exist: mov tag,1 ;此处输入代码段代码
done:
MOV AH,4CH
INT 21H
CODES ENDS
END START
·结果如下:b=8,a=2,c=5,因为8*8-4*2*5=24>0所以应该有解,tag为1
运行后,
Dds:0显示的数据第一排一次为2、8、5、1,前面三个是a、b、c的值,第四个是tag的值,值为1,符合题目要求
若改一改数据,将b改成2,结果应该为0
这里的tag果然为0,也符合题目要求。
2、编写一个程序,判别键盘上输入的字符;若是1-9 字符,则显示之;若为A-Z 字符,显
示“C”;若为a-z 字符,显示“c”;若是回车字符<CR>(其ASCII 码为0DH),则结束程序,
若为其它字符则显示显示“R”。
·源代码如下:
DATAS SEGMENT
char db ? ;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
l: mov ah,1
int 21h
mov char,al
cmp char,0dh
je end1
cmp char,'1';判断输入数是否比0大
jge next1
jmp others
next1:cmp char,'9';判断是否比9大
jle show1;不是的话,即在0~9之间,跳至show1
cmp char,'A';比9大后判断是否比41(‘A’)大
jge next2
jmp test1;不比40大,去检测是否是回车
next2: cmp char,'Z';比40大后,判断是否比5a(‘Z’)大
jle show2;不比5a(‘Z’)大,即在‘A’~‘Z’之间,跳至show2
cmp char,'a';判断是否比61(‘a’)大
jge next3;若大,跳至next3
jmp others
next3:cmp char,'z';检测是否比7a('z')大
jle show3;不比7a(‘z’)大,即在‘a’~‘z’之间跳至show3
jmp others
test1: cmp char,0dh
je end1
jmp others
show1: mov dl,char
mov ah,02h
int 21h
jmp done
show2: mov dl,'C'
mov ah,02h
int 21h
jmp done
show3: mov dl,'c'
mov ah,02h
int 21h
jmp done
others:mov dl,'R'
mov ah,02h
int 21h
jmp done
done:
loop l;输完一个字符之后,会立刻显示对应字符,此后可以继续输入字符。
end1:
;此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START
运行结果如下:
例如输入3,则立刻显示3(0~9显示原字符,输入),输入e之后显示‘c’(小写字母都显示c),输入S之后显示‘C’(大写字母显示C),输入@之后显示‘R’(其他字符统一显示R),如果按回车,则退出循环,如下
3、(大家再次编成实现实验一的题目,看是否可以优化程序?)分类统计字数组data 中正
数、负数和零的个数,并分别存入内存字变量Positive、Negative 和Zero 中,数组元素个
数保存在其第一个字中。使用Debug 查看Positive、Negative 和Zero 三个变量的数据。
·源代码如下:
DATAS SEGMENT
data1 dw 1,-2,-3,7,4,0,5
count equ ( $-data1)/2
positive dw count+1 dup(?)
negetive dw count+1 dup(?)
zero dw count+1 dup(?)
;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov dx,0
mov bx,0
mov di,0
mov si,0
mov cx,count
ll: mov ax,data1[si]
cmp ax,0
jg p
je z
jl n
p:mov ax,data1[si]
mov positive[si+2],ax
inc dx
add si,2
jmp l
z: mov ax,data1[si]
mov zero[si+2],ax
inc bx
add si,2
jmp l
n: mov ax,data1[si]
mov negetive[si+2],ax
inc di
add si,2
jmp l
l: loop ll
mov positive[0],dx
mov zero[0],bx
mov negetive[0],di;此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START
运行结果如下:
-dds:0里面显示的前面7个数为data1里面的,紧接着7个数是positive
4、编写程序,在字符串变量STRING 中存有一个以$为结尾的ASCII 码字符串,要求计算
字符串的长度,并把它存入LENGTH 单元中。(要求用条件控制循环方法,并且字符串分数
据类型是字节和字两种情况)
流程图:
情况1(字节)
·源代码:
DATAS SEGMENT
string db '13211$'
length1 db ?;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov al,0
mov si,0
count: cmp string[si],'$'
je done
inc si
inc al
jmp count
done:
mov length1,al
mov dl,al
mov ah,02h
int 21h;此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START
·运行结果为:
-dds:0中数据的第一行前面几个数是string,‘$’的ASCII码是24,之后的一个数据就是string中字节的个数,这里显示为5个(不含‘$’本身)
情况2(字)
·源代码:
DATAS SEGMENT
string dw '1','3','2','1','1','$'
length1 db ?;此处输入数据段代码
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
mov al,0
mov si,0
count: cmp string[si],'$'
je done
inc si
inc si
inc al
jmp count
done:
mov length1,al
mov dl,al
mov ah,02h
int 21h;此处输入代码段代码
MOV AH,4CH
INT 21H
CODES ENDS
END START
·运行结果如下:
前面的几个数据是string的数据,最后一个数0005是string中元素的个数,5个(这里依旧把‘$’算作其内)。
注意:涉及到初始数据的,同学们自行给出多组数据,反复加以验证各题程序。
五、实验要求与提示
1、实验要求
(1)画出各程序流程图;
(2)列出程序清单,加上适量注释;
(3)回答思考问题;
(4)记录实验结果;
(5) 完成实验报告(实验材料上的内容简写,自己的工作要详尽)。
2、实验提示:
A)二元一次方程有根的条件是B2-4*A*C>=0。依据题意,先计算出B2 和4*A*C,然
后比较两者大小,
B)字符输入输出
利用 DOS 的INT 21H 系统功能调用来实现字符的输入/输出操作,其中1 号功能表示
输入字符;2 号功能表示输出字符;详细查阅相关资料,简单示例:
(1)显示单个字符可以用DOS 的INT 21H 的2 号功能,将字符放在DL 寄存器中,2
号放在AH 寄存器中。
MOV DL,’*’
MOV AH,2
INT 21H__