⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 汇编代码.txt

📁 一个汇编语言学习的代码,包括学习,研究
💻 TXT
📖 第 1 页 / 共 4 页
字号:
例4.11b-1/2
	;主程序 
	call checksumb
	;子程序
checksumb	proc
	push ax
	push bx
	push cx
	xor al,al	;累加器清0
	mov bx,offset array
	;BX←数组的偏移地址
	mov cx,count
	;CX←数组的元素个数
例4.11b-2/2
sumb:	add al,[bx]	;求和
	inc bx
	loop sumb
	mov result,al	;保存校验和
	pop cx
	pop bx
	pop ax
	ret
checksumb	endp

主程序将子程序的入口参数压入堆栈,子程序从堆栈中取出参数
子程序将出口参数压入堆栈,主程序弹出堆栈取得它们

例4.11c
入口参数:
顺序压入偏移地址和元素个数
出口参数:
AL=校验和
例4.11c 主程序
	.startup
	mov ax,offset array
	push ax
	mov cx,count
	push cx
	call checksumc
	add sp,4
	mov result,al
	.exit 0
例4.11c 子程序
checksumc	proc
	push bp
	mov bp,sp	;利用BP间接寻址存取参数
	push bx
	push cx
	mov bx,[bp+6] 	;SS:[BP+6]指向偏移地址
	mov cx,[bp+4] 	;SS:[BP+4]指向元素个数
	xor al,al
sumc:	add al,[bx] 
	inc bx
	loop sumc
	pop cx
	pop bx
	pop bp
	ret
checksumc	endp
子程序的嵌套
子程序内包含有子程序
的调用就是子程序嵌套
没有什么特殊要求
例4.12嵌套子程序-1/2
ALdisp	proc	
	push ax
	push cx	;实现al内容的显示
	push dx
	push ax	;暂存ax
	mov dl,al	;转换al的高4位
	mov cl,4
	shr dl,cl
	call dldisp	;调用子程序显示al高4位
	pop ax	
	and dl,0fh
	call dldisp	;调用子程序显示al低4位
	pop dx
	pop cx
	pop ax
	ret
ALdisp	endp
例4.12嵌套子程序-2/2
;显示dl低4位中一位十六进制数
dldisp	proc
	or dl,30h
	cmp dl,39h
	jbe dldisp1
	add dl,7
dldisp1:	mov ah,2
	int 21h
	ret
dldisp	endp
子程序的递归
当子程序直接或间接地嵌套调用自身时称为递归调用,含有递归调用的子程序称为递归子程序
递归子程序必须采用寄存器或堆栈传递参数,递归深度受堆栈空间的限制

例4.13:求阶乘
例4.13 主程序-1/3
	.model small
	.stack 256
	.data
N	dw 3
result	dw ?
	.code
	.startup
	mov bx,N
	push bx	;入口参数:N
	call fact	;调用递归子程序
	pop result	;出口参数:N!
	.exit 0
例4.13 递归子程序-2/3
;计算N!的近过程
;入口参数:压入 N	;出口参数:弹出 N!
fact 	proc
	push ax
	push bp
	mov bp,sp
	mov ax,[bp+6] ;取入口参数 N
	cmp ax,0
	jne fact1	;N>0,N!=N×(N-1)!
	inc ax	;N=0,N!=1
	jmp fact2
例4.13 递归子程序-3/3
fact1:	dec ax	;N-1
	push ax
	call fact	;调用递归子程序求(N-1)!
	pop ax
	mul word ptr [bp+6]	;求 N×(N-1)!
fact2:	mov [bp+6],ax	;存入出口参数 N!
	pop bp
	pop ax
	ret
fact	endp
递归子程序
子程序的重入
子程序的重入是指子程序被中断后又被中断服务程序所调用,能够重入的子程序称为可重入子程序。在子程序中,注意利用寄存器和堆栈传递参数和存放临时数据,而不要使用固定的存储单元(变量),就能够实现重入。
子程序的重入不同于子程序的递归。重入是被动地进入,而递归是主动地进入;重入的调用之间往往没有关系,而递归的调用之间却是密切相关的。递归子程序也是可重入子程序。
子程序补充例题1
子程序从键盘输入一个有符号十进制数;子程序还包含将ASCII码转换为二进制数的过程
输入时,负数用“-”引导,正数直接输入或用“+”引导
子程序用寄存器传递出口参数,主程序调用该子程序输入10个数据
补充例题1-1/5
	.data
count	equ 10
array	dw count dup(0)	;预留数据存储空间
	.code
	.startup
	mov cx,count
	mov bx,offset array
again:	call read	;调用子程序输入一个数据
	mov [bx],ax	;将出口参数存放缓冲区
	inc bx
	inc bx
	call dpcrlf
;调用子程序,光标回车换行以便输入下一个数据
	loop again
	.exit 0
补充例题1-2/5
;输入有符号10进制数的通用子程序
;出口参数:AX=补码表示的二进制数值
;说明:负数用“-”引导,正数用“+”引导或直接输入;数据范围是+32767~-32768
read	proc
	push bx
	push cx
	push dx
	xor bx,bx	;BX保存结果
	xor cx,cx
	;CX为正负标志,0为正,-1为负
	mov ah,1	;输入一个字符
	int 21h
补充例题1-3/5
	cmp al,'+'	;是“+”,继续输入字符
	jz read1
	cmp al,'-'	;是“-”,设置-1标志
	jnz read2	;非“+”和“-”,转read2
	mov cx,-1
read1:	mov ah,1	;继续输入字符
	int 21h
read2:	cmp al,'0 '
	;不是0~9之间的字符,则输入数据结束
	jb read3
	cmp al,'9'
	ja read3
补充例题1-3/5
	cmp al,'+'	;是“+”,继续输入字符
	jz read1
	cmp al,'-'	;是“-”,设置-1标志
	jnz read2	;非“+”和“-”,转read2
	mov cx,-1
read1:	mov ah,1	;继续输入字符
	int 21h
read2:	cmp al,'0 '
	;不是0~9之间的字符,则输入数据结束
	jb read3
	cmp al,'9'
	ja read3
补充例题1-4/5
	sub al,30h
;是0~9之间的字符,则转换为二进制数
;利用移位指令,实现数值乘10:BX←BX×10
	shl bx,1
	mov dx,bx
	shl bx,1
	shl bx,1
	add bx,dx
	;BX乘2与BX乘8相加
	mov ah,0
	add bx,ax
;已输入数值乘10后,与新输入数值相加
	jmp read1	;继续输入字符
补充例题1-5/5
read3:	cmp cx,0
	jz read4
	neg bx	;是负数,进行求补
read4:	mov ax,bx	;设置出口参数
	pop dx
	pop cx
	pop bx
	ret	;子程序返回
read	endp
	;使光标回车换行的子程序
dpcrlf	proc
	...	;省略
dpcrlf	endp
	end
ASCII码转换为二进制数
① 首先判断输入为正或负数,并用一个寄存器记录
② 接着输入0~9数字(ASCII码),并减30H转换为二进制数
③ 然后将前面输入的数值乘10,并与刚输入的数字相加得到新的数值
④ 重复②、③步,直到输入一个非数字字符结束
⑤ 负数进行求补,转换成补码;否则直接保存数值
本例采用16位寄存器表达数据,
所以只能输入+327677~-32768间的数值
但该算法适合更大范围的数据
子程序补充例题2
子程序在屏幕上显示一个有符号10进制数;子程序还包含将二进制数转换为ASCII码的过程
显示时,负数用“-”引导,正数直接输出、没有前导字符
子程序的入口参数用共享变量传递,主程序调用该子程序显示10个数据
补充例题2-1/5
	.data
count	= 10
array	dw 1234,-1234,0,1,-1,32767
	dw -32768,5678,-5678,9000
wtemp	dw ?	;共享变量
	.code
	.startup
	mov cx,count
	mov bx,offset array
again:	mov ax,[bx]
	mov wtemp,ax	;将入口参数存入共享变量
	call write	;调用子程序显示一个数据
	inc bx
	inc bx
	call dpcrlf	;便于显示下一个数据
	loop again
	.exit 0
补充例题2-2/5
;显示有符号10进制数的通用子程序
;入口参数:共享变量wtemp
write	proc
	push ax
	push bx
	push dx
	mov ax,wtemp	;取出显示数据
	test ax,ax	;判断零、正数或负数
	jnz write1
	mov dl,'0'	;是零,显示“0”后退出
	mov ah,2
	int 21h
	jmp write5
补充例题2-3/5
write1:	jns write2	;是负数,显示“-”
	mov bx,ax	;AX数据暂存于BX
	mov dl,'-'
	mov ah,2
	int 21h
	mov ax,bx
	neg ax	;数据求补(求绝对值)
write2:	mov bx,10
	push bx
	;10压入堆栈,作为退出标志
补充例题2-4/5
write3:	cmp ax,0	;数据(余数)为零
	jz write4	;转向显示
	sub dx,dx	;扩展被除数DX.AX
	div bx	;数据除以10:DX.AX÷10
	add dl,30h
	;余数(0~9)转换为ASCII码
	push dx
	;数据各位先低位后高位压入堆栈
	jmp write3
write4:	pop dx
	;数据各位先高位后低位弹出堆栈
	cmp dl,10	;是结束标志10,则退出
	je write5
补充例题2-5/5
	mov ah,2	;进行显示
	int 21h
	jmp write4
write5:	pop dx
	pop bx
	pop ax
	ret	;子程序返回
write	endp
	;使光标回车换行的子程序
dpcrlf	proc
	...	;省略
dpcrlf	endp
	end
二进制数转换为ASCII码
① 首先判断数据是零、正数或负数,是零显示“0”退出
② 是负数,显示“-”,求数据的绝对值;
③ 接着数据除以10,余数加30H转换为ASCII码压入堆栈
④ 重复③步,直到余数为0结束
⑤ 依次从堆栈弹出各位数字,进行显示
本例采用16位寄存器表达数据,所以只能显示+327677~-32768间的数值
但该算法适合更大范围的数据
子程序补充例题3
子程序将16位有符号二进制数求和,然后除以数据个数得到平均值
子程序的入口参数利用堆栈传递,主程序需要压入数据个数和数据缓冲区的偏移地址。子程序通过BP寄存器从堆栈段相应位置取出参数
子程序的出口参数用寄存器AX传递
主程序提供10个数据,并保存平均值
补充例题3-1/4
	.data
count	= 10
array	dw 1234,-1234,0,1,-1,32767
	dw -32768,5678,-5678,9000
wmed	dw ?	; 存放平均值
	.code
	.startup
	mov ax,count
	push ax	;压入数据个数
	mov ax,offset array
	push ax	;压入缓冲区偏移地址
	call mean	;调用子程序求平均值
	add sp+4	;平衡堆栈
	mov wmed,ax	;保存平均值(不含余数)
	.exit 0
补充例题3-2/4
;计算16位有符号数平均值子程序
;入口参数:顺序压入数据个数和缓冲区偏移地址
;出口参数:AX=平均值
mean	proc	
	push bp
	mov bp,sp
	push bx	;保护寄存器
	push cx
	push dx
	push si
	push di
补充例题3-3/4
	mov bx,[bp+4] ;从堆栈取出偏移地址
	mov cx,[bp+6] ;从堆栈取数据个数
	xor si,si	;SI保存求和的低16位值
	mov di,si	;DI保存求和的高16位值
mean1:	mov ax,[bx]	;取出一个数据→AX
	cwd	;符号扩展→DX
	add si,ax	;求和低16位
	adc di,dx	;求和高16位
	inc bx	;指向下一个数据
	inc bx
	loop mean1	;循环
补充例题3-4/4
	mov ax,si
	mov dx,di	;累加和在DX.AX
	mov cx,[bp+6]	;数据个数在CX
	idiv cx
;有符号数除法,求的平均值在AX中、余数在DX中
	pop di	;恢复寄存器
	pop si
	pop dx
	pop cx
	pop bx
	pop bp
	ret
mean	endp
	end
补充例题3的堆栈区
有符号数如何避免溢出
为了避免有符号二进制数求和过程中溢出,被加数要进行符号扩展,得到倍长数据(大小没有变化),然后求和
因为采用16位二进制数表示数据个数,最大是216,这样扩展到32位二进制数表达累加和,不再会出现溢出
考虑极端情况:数据全是-215,共有216个,求和结果是-231,32位数据仍然可以表达
第4章 教学要求(1)
第4章 教学要求(2)
熟悉常见程序设计问题:
多精度运算、查表(查代码、特定值等)
ASCII、BCD及十六进制数据间的代码转换
数据范围判断(0~9、A~Z、a~z)
字母大小写转换;字符串传送、比较等操作
求最小最大值、数据求和、统计字符个数
子程序的寄存器和共享变量传递参数






1、编写一程序段,将AL中的第7位和第0位,第6位和第1位,第5位和第2位,第4位和第3位互换。
解:类似于课本习题“7.2”
  mov cx,8
  mov ah,0
k1: shr al,1
  rcl ah,1
  dec cx
  jnz k1
  mov al,ah
2、在A1单元开始定义了一长度为N的字符串,找出其中所有的小写字母并存放到A2单元开始的存储区中。统计出小写字母的个数,存放到SL单元中。请编写一完整的源程序。数据段如下:
data segment
A1 db 'ab1243AdcBBcdEd94r3'
N equ $-A1
A2 db N dup(?)
Sl db ?
data ends

解:
data segment      ;数据段
A1 db 'ab1243AdcBBcdEd94r3'
N equ $-A1
A2 db N dup(?)
Sl db ?
data ends

code segment      ;代码段
assume cs:code, ds:data
main: mov ax,data
   mov ds,ax
   lea si,a1
   lea di,a2
   mov cx,N
   xor bl,bl
lab1: mov al,[si]
   cmp al,'a'
   jb lab2
   cmp al,'z'
   ja lab2
   mov [di],al
   inc bl
   inc di
lab2: inc si
   loop lab1
   mov sl,bl

   mov ah,2     ;以下程序段可以不写,只是利用输出屏幕验证题目的正确性。
   mov cx,N
   lea bx,a1
lab3: mov dl,[bx]
   int 21h
   inc bx
   loop lab3

   call cr

   mov ah,2
   mov ch,0
   mov cl,[sl]
   lea bx,a2
lab4: mov dl,[bx]
   int 21h
   inc bx
   loop lab4

   call cr

   mov ah,0
   mov al,[sl]
   call write

   mov ah,4ch
   int 21h
   include cr.asm
   include write.asm
code ends
end main

1、设在数据段中有X,Y两个变量(字节单元),试编写程序段计算:
y=x  当x>=0时
 |x| 当x<0时

解:mov ax,x
  cmp al,0
  jge lab
  neg al
lab:mov y,al
2、编写一个完整的源程序,将BUF字节单元存放的两位BCD码,转换成2个字节的ASCII码,并分别存放在ASC和ASC+1字节单元中。
例如:(BUF字节单元)=58H,那么(ASC字节单元)=35H,(ASC+1字节单元)=38H。

data segment
buf db 58h
asc db 2 dup(?)
data ends

code segment
assume cs:code, ds:data
main: mov ax,data
   mov ds,ax
   mov al,buf
   and al,0f0h
   shr al,cl
   or al,30h
   mov asc,al
   mov al,buf
   and al,0fh
   or al,30h
   mov asc+1,al
   mov ah,4ch
   int 21h
code ends
end main
1、设在DAT1,DAT2字单元中存放一双字长有符号数,编一程序段,完成求出该双字长数的绝对值后送ABS1和ABS2字存储单元。

start:mov ax,dat1    ;AX放低位字有符号数

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -