(十六)不同的寻址方式的灵活应用--汇编笔记

汇编语言

Posted by YiMiTuMi on March 26, 2020

不同的寻址方式的灵活应用

 1) [idata]用一个常量来表示地址,可以直接定位一个内存单元。(注意编译器的差别)

 2)[bx]用一个变量来表示内存地址,可以间接定位一个内存单元。

 3)[bx + idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元。

 4)[bx + si]用两个变量表示地址。

 5)[bx + si + idata]用两个变量和一个常量表示地址。

例1:将datasg段中每个单词的头一个字母改为大写字母。

assume cs:codesg, da:datasg

datasg segment

	db '1. file         '
	db '2. edit         '
	db '3. search       '
	db '4. view         '
	db '5. options      '
	db '6. help         '

datasg ends

datasg中定义了6个字符串,每个长度为16个字节。(后面用空格填充)因为它们是连续存放的可以将6个字符串看成一个6行16列的二维数组。也就变成了需要修改每一行的第4列的字符。(相对于首行的偏移地址为3)

assume cs:codesg, da:datasg
	
datasg segment
	
	db '1. file         '
	db '2. edit         '
	db '3. search       '
	db '4. view         '
	db '5. options      '
	db '6. help         '
	
datasg ends

codesg segment

	start:  mov ax, datasg
			mov ds, ax

			mov bx, 0

			mov cx, 6

		s:  mov al, [bx + 3]
			and al, 11011111B //2进制
			mov [bx + 3], al
			add bx, 16
			loop s

			mov ax, 4C00H
			int 21H

codesg ends

end start

例2:将datasg段中每个单词改为大写字母(没有保存寄存器cx导致循环错误)

assume cs:codesg, da:datasg

datasg segment

	db 'file            '
	db 'edit            '
	db 'search          '
	db 'view            '

datasg ends

看作数组的话要进行双重循环,即4行n列,即循环4*3次。

assume cs:codesg, da:datasg
	
datasg segment
	
	db 'fil             '
	db 'edi             '
	db 'sea             '
	db 'vie             '
	
datasg ends

codesg segment

	start:  mov ax, datasg
		 	mov ds, ax

			mov cx, 4
			
			mov si, 0
		//外层
	   s0:  mov cx, 3 		//重置cx 计数
			mov bx, 0       //重置列

		//内层循环,循环行
		s:  mov al, [bx + si]
			and al, 11011111B
			mov [bx + si], al
			inc bx
			
			loop s
			
			add si, 16   //增加行
			
			loop s0

			mov ax, 4c00H
			int 21H

codesg ends

end start

以上程序有问题,cx代表了loop循环的计数,在内层循环的时候会导致内从循环覆盖了外层循环。因为不能多用一个计数器,所以我们要在内层循环开始时,保存外层循环的cx值。在执行外层循环loop前,再恢复外层循环的cx值。

改进(用dx寄存器保存cx中的值):

assume cs:codesg, da:datasg
	
datasg segment
	
	db 'fil             '
	db 'edi             '
	db 'sea             '
	db 'vie             '
	
datasg ends

codesg segment

	start:  mov ax, datasg
		 	mov ds, ax
			
			mov cx, 4
			
			mov si, 0
		//外层
	   s0:  mov dx, cx       //保存外层循环的计数器的值,第一次会保存初始化的值,后面会保存减1的值
			mov cx, 3 		//重置cx 计数
			mov bx, 0       //重置列

		//内层循环,循环行
		s:  mov al, [bx + si]
			and al, 11011111B
			mov [bx + si], al
			inc bx
			
			loop s
			
			add si, 16   //增加行,换行
			mov cx, dx   //将计数器的值拿出				
			
			loop s0		 //这里会判断计数器的值,并减1
			

			mov ax, 4c00H
			int 21H

codesg ends

end start

改进(开辟一段空间来保存cx的值):

assume cs:codesg, da:datasg
	
datasg segment
	
	db 'fil             '
	db 'edi             '
	db 'sea             '
	db 'vie             '
	
	dw 0		//定义一个字来暂存cx

datasg ends

codesg segment

	start:  mov ax, datasg
		 	mov ds, ax
			
			mov cx, 4
			
			mov si, 0
		//外层
	   s0:  mov ds:[0040H], cx       //保存外层循环的计数器的值,第一次会保存初始化的值,后面会保存减1的值(用开辟地内存保存)
			mov cx, 3 		//重置cx 计数
			mov bx, 0       //重置列

		//内层循环,循环行
		s:  mov al, [bx + si]
			and al, 11011111B
			mov [bx + si], al
			inc bx
			
			loop s
			
			add si, 16   //增加行
			mov cx, ds:[0040H]   //将计数器的值拿出(用开辟地内存保存)				
			loop s0		 //这里会判断计数器的值,并减1
			

			mov ax, 4c00H
			int 21H

codesg ends

end start

一般来说,在需要暂存数据的时候,我们都应该使用栈。

改进(用栈来保存):

assume cs:codesg, da:datasg, ss:stacksg
	
datasg segment
	
	db 'fil             '
	db 'edi             '
	db 'sea             '
	db 'vie             '

datasg ends

stacksg segment

	dw 0,0,0,0,0,0,0,0 //定义一个段,用来做栈段,容量为16个字节

stacksg ends

codesg segment

	start:  mov ax, datasg
		 	mov ds, ax
			//栈设置			
			mov ax, stacksg
			mov ss, ax
			mov sp, 16 //栈底

			mov cx, 4
			mov si, 0

		//外层
	   s0:  push cx       //保存外层循环的计数器的值,第一次会保存初始化的值,后面会保存减1的值(入栈)
			mov cx, 3 		//重置cx 计数
			mov bx, 0       //重置列

		//内层循环,循环行
		s:  mov al, [bx + si]
			and al, 11011111B
			mov [bx + si], al
			inc bx
			
			loop s
			
			add si, 16   //增加行
			pop cx  //将计数器的值拿出(出栈)	
		
			loop s0		 //这里会判断计数器的值,并减1
			

			mov ax, 4c00H
			int 21H

codesg ends

end start

例3:编程,将datasg段中每个单词的前4个字母改为大写字母

assume cs:codesg, da:datasg, ss:stacksg
	
datasg segment
	
	db '1.display       '
	db '2.brows         '
	db '3.replace       '
	db '4.modify        '
	
	dw 0		//定义一个字来暂存cx

datasg ends

stacksg segment

	dw 0,0,0,0,0,0,0,0 //定义一个段,用来做栈段,容量为16个字节

stacksg ends

codesg segment
			
			//数据段
	start:  mov ax, datasg
			mov ds, ax
			//栈段
			mov ax, stacksg
			mov ss, ax
			mov sp, 16  //栈底
			mov bx, 0				
			mov si, 0

			mov cx, 4
			//外层循环
		s:  push cx   //保存外从循环的计数器值	
			mov cx, 4
		
	   s0:	mov al, [bx + si + 3]
			and al, 11011111B //转大写
			mov [bx + si + 3], al
			inc si
			loop s0

			mov si, 0
			mov add, 16
			pop cx
			loop s
			
			mov ax, 40cH
			int 21H
codesg ends
end start

水晶花 – 谢谢你的爱、有你真精彩