汇编语言复习摘要七——更灵活的定位内存地址方法
1. 以字符形式给出的数据:在汇编程序中,以'...'方式指明的数据是以字符形式给出的,编译器把它们转化为响应的ASCII码。
assume cs:code
code segment
start:
mov al, 'a'
mov bl, 'b'
mov ax, 4c00h
int 21h
code ends
end start
2. 大小写转换的问题:大小写字母的二进制码其实只有第5个bit(从0开始算起)是不同的,小写的字母第5个bit总是为1,而大写的总是为0. 所以,转换大小写无需判断字母是大写还是小写。and和or指令按位进行与或者或计算。下面是把字符串中的每个字符都转换成小写字母的程序:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
assume cs:code, ds:data
data segment
db 'BaSic'
data ends
code segment
start:
mov ax, data
mov ds, ax
mov cx, 5
mov bx, 0
s:
mov al, [bx]
or al, 00100000B
mov [bx], al
inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
3. [bx + idata]:仍然表示一个内存单元,只不过这个内存单元的地址是:bx + idata;同样可以写成:
mov ax, [200 + bx]; mov ax, 200[bx]; mov ax, [bx].200
4. 用[bx+idata]方式进行更加灵活的数组处理:示例:假设有两个字符串,需要你在一个循环里面把这两个字符串进行这样的转换:第一个字符串全部转换成小写,第二个字符串全部转换为大写。
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
assume cs:code, ds:data
data segment
db 'BaSic'
db 'fOrK'
data ends
code segment
start:
mov ax, data
mov ds, ax
mov cx, 5
mov bx, 0
s:
mov al, [0+bx]
or al, 00100000B
mov [0+bx], al
mov al, [5+bx]
and al, 11011111B
mov [5+bx], al
inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
5. SI/DI:SI/DI 同样也是寄存器,而且跟BX功能相近,只是SI和DI不能分成两个8位的寄存器,而BX可以。
下面用SI/DI把字符串"welcome to masm!"复制到它后面的数据区里面:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
assume cs:code, ds:data
data segment
db 'welcome to masm!'
db '................'
data ends
code segment
start:
mov ax, data
mov ds, ax
mov si, 0
mov cx, 16
s:
mov al, [0 + si]
mov [16+si], al
inc si
loop s
mov ax, 4c00h
int 21h
code ends
end start
6. [bx+si]/[bx+di] and [bx+si+idata]/[bx+di+idata]:含义类似,表示:bx+si的值/bx+si+idata的值。要注意的是,只能是bx跟si/di混合使用,不能混合使用si和di,例如:[si + di]并不合法。
7. 练习:将数据段中的英文字母全部改为大写,代码:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
assume cs:code, ds:data, ss:stack
stack segment
dw 0, 0, 0, 0, 0, 0, 0, 0
stack ends
data segment
db 'abc '
db 'efg '
db 'hij '
db 'klm '
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 16
mov cx, 4
s0:
push cx
mov si, 0
mov cx, 3
s:
mov al, [bx+si]
and al, 11011111B
mov [bx+si], al
inc si
loop s
pop cx
add bx, 6
loop s0
mov ax, 4c00h
int 21h
code ends
end start
思路:需要用到两重循环,这在高级语言中是非常简单的事情。在汇编中,循环计数只能用CX寄存器,那么两重循环势必都要用到CX的值。然而,如果没有把CX的值保存起来,那么将会造成CX的值改变了,也达不到我们的目的。所以,如何保存CX的值成为程序的关键。
假如把CX存在数据段中,是可以,但是你必须记住存在数据段中哪一个地址,这样势必就会造成我们程序编写上的困难。所以一般我们的方法是把临时变量存储在栈上面,这跟高级语言的道理是一样的。像C语言,我们把临时变量存储在栈上面,等到函数结束,也就销毁了临时变量。所以,我们要把CX的值存储在栈上面。在汇编中,栈空间是要自己来定义的。所以我们定义了一个16个字节长度的栈空间,用来存储CX值;要注意的是,入栈之后要出栈还给CX的值。结果如下:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
-d 13F2:0
13F2:0000 41 42 43 20 20 20 45 46-47 20 20 20 48 49 4A 20 ABC EFG HIJ
13F2:0010 20 20 4B 4C 4D 20 20 20-00 00 00 00 00 00 00 00 KLM ........
13F2:0020 B8 F2 13 8E D8 B8 F1 13-8E D0 BC 10 00 B9 04 00 ................
8. 练习:下面我把教材中的练习题做了一次,跟上一题差不多,只是把字符串前4个改为大写而已。代码:
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
assume cs:code, ds:data, ss:stack
stack segment
dw 0, 0, 0, 0, 0, 0, 0, 0
stack ends
data segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
data ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
mov sp, 16
mov cx, 4
mov bx, 3
s0:
push cx
mov cx, 4
mov si, 0
s:
mov al, [bx+si]
and al, 11011111b
mov [bx+si], al
inc si
loop s
pop cx
add bx, 14
loop s0
mov ax, 4c00h
int 21h
code ends
end start