7.10 不同的寻址方式的灵活应用
如果我们比较一下前面用到的几种定位内存地址的方法(可称为寻址方式),就可以发现:
[idata]
用一个常量来表示地址,可用于直接定位一个内存单元;
[bx]
用一个变量来表示内存地址,可用于间接定位一个内存单元;
[bx+idata]
用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元;
[bx+si]
用两个变量表示地址;
[bx+si+idata]
用两个变量和一个常量表示地址。
可以看到,从[idata]
一直到[bx+si+idata]
,我们可以用更加灵活的方式来定位一个内存单元的值。这使我们可以从更加结构化的角度来看待所要处理的数据。下面我们通过一个问题的系列来体会CPU提供更多寻址方式的用意,并学习一些相关的编程技巧。
问题 7.6
编程,将datasg段中每个单词的头一个字母改成大写字母。
assume cs:codesg,ds: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:
codesg ends
end start
分析:
datasg中的数据的存储结构,如图7.2所示。
我们可以看到,在datasg中定义了6个字符串,每个长度为16字节(注意,为了直观,每个字符串的后面都加上空格符,以使它们的长度刚好为16个字节)。因为它们是连续存放的,可以将6个字符串看成一个6行16列的二位数组。按照要求,需要修改每个单词的第一个字母,即二位数组的每一行的第4列(相对于首行的偏移地址为3)。
我们需要进行6次循环,用一个变量R定位行,用常量3定位列。处理的过程如下。
R = 第一行地址
mov cx,6
s: 改变R行,3列的字母为大写
R=下一行的地址
loop s
我们用bx作变量,定位每行的起始地址,用3定位要修改的列,用[bx+idata]的方式来对目标单元进行寻址,程序如下。
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,6
s: mov al,[bx+3]
and al,11011111b
mov [bx+3],al
add bx,16
loop s
问题7.7
编程,将datasg段中每个单词改成大写字母。
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends
codesg segment
start:
codesg ends
end start
分析:
datasg中的数据的存储结果如图7.3所示。
在datasg中定义了4个字符串,每个长度为16个字节(注意,为了使我们在debug中可以直观的查看,每个字符串的后面都加上了空格符,以使它们的长度刚好为16个字节)。因为它们是连续存放的,我们可以将这4个字符串看成一个4行16列的二位数组。按照要求,我们需要修改每一个单独,即二位数组的每一行的前3列。
我们需要进行4x3次的二重循环,用变量R定位行,变量C定位列。外层循环按行来进行,内层按列来进行。首先用R定位第1行,然后循环修改R行的前3列;然后再用R定位到下一行,再次循环修改R行的前3列……,如此重复直到所有的数据修改完毕。处理的过程大概如下。
R=第一行的地址;
mov cx,2
s0: C=第一列的地址
mov cx,2
s: 改变R行,C列的字母为大写
C=下一列地址;
loop s
R=下一行的地址
loop s0
我们用bx来作变量,定位每行的起始地址,用si定位要修改的列,用[bx+si]的方式来对目标单元进行寻址,程序如下。
mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4
s0: mov si,0
mov cx,3
s: mov al,[bx+si]
and al,11011111b
mov [bx+si],al
inc ai
loop s
add bx,16
loop s0