[toc]

更灵活的定位内存地址的方法


1、and 和 or

and指令:逻辑与指令,按位进行与运算。

1
2
mov al, 01100011B
and al, 00111011B

执行后:al=00100011B即都为1才为1

or指令:逻辑或指令,按位进行或运算。

mov al, 01100011B or al, 00111011B 执行后:al=01111011B 即只要有一个为1就为1

关于ASCII码 世界上有很多编码方案,有一种方案叫做ASCII编码,是在计算机系统中通常被采用的。简单地说,所谓编码方案,就是一套规则,它约定了用什么样的信息来表示现实对象。比如说,在ASCII编码方案中,用61H表示“a”,62H表示“b”。一种规则需要人们遵守才有意义。

在文本编辑过程中,我们按一下键盘的a键,就会在屏幕上看到“a”。我们按下键盘的a键,这个按键的信息被送入计算机,计算机用ASCII码的规则对其进行编码,将其转化为61H存储在内存的指定空间中;文本编辑软件从内存中取出61H,将其送到显卡上的显存中;工作在文本模式下的显卡,用ASCII码的规则解释显存中的内容, 61H被当作字符“a”,显卡驱动显示器,将字符“a”的图像画在屏幕上。我们可以看到,显卡在处理文本信息的时候,是按照ASCII码的规则进行的。这也就是说,如果我们要想在显示器上看到“a”,就要给显卡提供“a”的ASCIⅡ码,61H。如何提供?当然是写入显存中。

以字符形式给出的数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
assume cs:code,ds:data 

data segment 
	db 'unIx'   ;相当于“db 75H,6EH,49H,58H”
	db 'foRK'
data ends 

code segment
start:	mov al, 'a'  ;相当于“mov al, 61H”,“a”的ASCI码为61H;
		mov b1, 'b'
		
		mov ax, 4c00h 
		int 21h 
code ends
end start

大小写转换的问题 在这里插入图片描述 小写字母的ASCII码值比大写字母的ASCII码值大20H

大写字母ASCII码的第5位为0,小写字母的第5位为1(其他一致)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
assume cs:codesg,ds:datasg 

datasg segment 
	db 'BaSiC'
	db 'iNfOrMaTion'
datasg end

codesg segment 
	start:	mov ax, datasg 
			mov ds, ax	;设置ds 指向 datasg段
		
			mov bx, 0	;设置(bx)=0,ds:bx指向’BaSic’的第一个字母
			
			mov cx, 5     	 ;设置循环次数5,因为’Basic'有5个字母
	s:		mov al, [bx]     ;将ASCII码从ds:bx所指向的单元中取出
			and al, 11011111B;将al中的ASCII码的第5位置为0,变为大写字母
			mov [bx], al	 ;将转变后的ASCII码写回原单元
			inc bx		     ;(bx)加1,ds:bx指向下一个字母
			loop s 
			
			mov bx, 5	;设置(bx)=5,ds:bx指向,iNfOrMaTion'的第一个字母
			
			mov cx, 11	;设置循环次数11,因为‘iNfOrMaTion'有11个字母
	s0:		mov al, [bx]
			or al, 00100000B;将a1中的ASCII码的第5位置为1,变为小写字母
			mov [bx], al 
			inc bx
			loop s0
			
			mov ax, 4c00h 
			int 21h 
codesg ends

2、[bx+idata]

[bx+idata]表示一个内存单元, 例如:mov ax, [bx+200] 该指令也可以写成如下格式:

1
2
3
4
5
mov ax, [200+bx]

mov ax, 200[bx]

mov ax, [bx].200

用[bx+idata]的方式进行数组的处理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
assume cs:codesg,ds:datasg 

datasg segment 
	db 'BaSiC';转为大写
	db 'MinIx';转为小写
datasg ends

codesg segment
	start:
		mov ax, datasg 
		mov ds, ax 
		mov bx, 0  ;初始ds:bx
	
		mov cx, 5
	s:	mov al, 0[bx]  
		and al, 11011111b ;转为大写字母
		mov 0[bx], al ;写回
		mov al, 5[bx]  ;[5 + bx]
		or al, 00100000b ;转为小写字母
		mov 5[bx], al 
		inc bx
		loop s
		
		mov ax, 4c00h 
		int 21h
codesg ends
end start

C语言描述

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
int main()
{
	char a[] = "BaSic";
	char b[] = "MinIX";
	
	int i = 0;
	
	do
	{
		a[i] = a[i] & 0xDF;
		b[i] = b[i] | 0x20;
		i++;
	} while(i < 5);

	return 0;
 } 

3、SI 、DI 与 寻址方式的灵活应用

1、si 、di

si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
assume cs: codesg, ds: datasg 

datasg segment 
	db 'welcome to masm!';用si和di实现将字符串‘welcome to masm!"复制到它后面的数据区中。
	db '................'
datasg ends

codesg segment 
	start:	mov ax, datasg 
			mov ds, ax 
			mov si, 0
			
			mov cx, 8
	s:		mov ax, 0[si] ;[0 + si]
			mov 16[si], ax ;[16 + si] 使用[bx +idata]方式代替di,使程序更简洁
			add si, 2 
			loop s 
			
			mov ax, 4c00h 
			int 21h 
codesg ends 
end start

2、[bx + si] 和 [bx + di]

[bx+si]和[bx+di]的含义相似

[bx+si]表示一个内存单元,它的偏移地址为(bx)+(si)

指令mov ax, [bx + si]的含义:将一个内存单元字数据的内容送入ax,段地址在ds中

该指令也可以写成如下格式:mov ax, [bx][si]

3、[bx+si+idata]和[bx+di+idata] [bx+si+idata]表示一个内存单元,它的偏移地址为(bx)+(si)+idata

指令mov ax,[bx+si+idata]的含义:将一个内存单元字数据的内容送入ax,段地址在ds中

4、不同的寻址方式的灵活应用 [idata]用一个常量来表示地址,可用于直接定位一个内存单元; [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元; [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元; [bx+si]用两个变量表示地址; [bx+si+idata]用两个变量和一个常量表示地址。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
;将datasg段中每个单词改为大写字母
assume cs:codesg,ds:datasg,ss:stacksg 

datasg segment
	db 'ibm            ' ;16
	db 'dec            ' 
	db 'dos            '
	db 'vax            '  ;看成二维数组
datasg ends 

stacksg segment ;定义一个段,用来做栈段,容量为16个字节
	dw 0, 0, 0, 0, 0, 0, 0, 0
stacksg ends 

codesg segment 
	start:	mov ax, stacksg 
			mov ss, ax
			mov sp, 16 
			mov ax, datasg 
			mov ds, ax 
			mov bx, 0 ;初始ds:bx
			
			;cx为默认循环计数器,二重循环只有一个计数器,所以外层循环先保存cx值,再恢复,我们采用栈保存
			mov cx, 4
	s0:		push cx	;将外层循环的cx值入栈
			mov si, 0
			mov cx, 3	;cx设置为内层循环的次数
	s:		mov al, [bx+si]
			and al, 11011111b ;每个字符转为大写字母
			mov [bx+si], al 
			inc si
			loop s 
			
			add bx, 16 ;下一行
			pop cx	;恢复cx值
			loop s0 ;外层循环的loop指令将cx中的计数值减1
			
			mov ax4c00H 
			int 21H 
codesg ends
end start

4、总结

  • 本章介绍了一些地址定位的方式
  • 对于数据暂存最好不要使用寄存器,因为寄存器资源有限。应该使用栈作为数据暂存的选择