更灵活的定位内存地址的方法
以字符形式给出的数据:
使用关键字db
assume cs:code
data segment
db 'unix'
db 'fork'
data ends
code segment
start: mov al, 'a'
mov bl, 'b'
mov ax, 4c00h
int 21h
code ends
end start
查看ds+10h段内存单元
实现大小写的转换
观察大小写字母的ASCII码值可以发现,大写字母和小写字母的第5位ASCII码值是不一样的,也就是小写字母正好比大写字母的ASCII**大20H**
所以我们只需要使用AND和OR操作来改变第5位的值就行了
assume cs:codesg, ds:datasg
datasg segment
db 'BaSiC'
db 'iNfOrMaTiOn'
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 5 ;将BaSiC转换为basic
s: mov al, [bx]
and al, 11011111B
mov [bx], al
inc bx
loop s
mov bx, 5
mov cx, 11 ;将iNfOrMaTiOn转换为INFORMATION
s0: mov al, [bx]
or al, 00100000B
mov [bx], al
inc bx
loop s0
mov ax, 4c00h
int 21h
codeseg ends
end start
程序执行完毕之后,BaSiC和iNfOrMaTiOn分别被改成了大写和小写
下面给出了一种更加灵活的定位内存单元的方法
mov ax, [200+bx]
mov ax, 200[bx]
;这个形式和高级语言中的a[i]、b[i]非常相像
mov ax, [bx].200
这上面三中写法其实是一个意思:
将段地址为ds,偏移地址为200+bx的内存单元中的数值存到寄存器ax中
有了这种定位内存位置的方式,我们就可以处理数组了,是用这种方式,上面的那段大小写转换程序不需要使用设置两个循环了
代码如下:(处理的两个单词的长度必须是一样的。。。。)
assume cs:code, ds:datasg
datasg segment
db 'BaSiC'
db 'MinIX'
datasg ends
code segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 5
s: mov al, [bx]
and al, 11011111b
mov [bx], al
mov al, [5+bx]
or al, 00100000b
mov [5+bx], al
inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
处理前:
处理后:
嵌套循环(双层循环)
程序代码:
assume cs:code, ds:datasg
datasg segment
db 'file '
db 'file '
db 'file '
db 'file '
db 'file '
db 'file '
;将这六行每一行的前四个单词变成大写
datasg ends
code segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 6
s0: mov dx, cx
mov si, 0
mov cx, 4
s: mov al, [bx+si]
and al, 11011111b
mov [bx+si], al
inc si
loop s
add bx, 10h
mov cx, dx
loop s0
mov ax, 4c00h
int 21h
code ends
end start
处理前:
处理后:
注意:我们这段程序只是两层嵌套,必然需要使用两个循环因子,我们上面的这段程序使用的是寄存器,但是CPU中的寄存器的数量是有限的,当我们的程序非常复杂的时候,使用寄存器来做循环因子就不那么现实了,这时候我们就寻要用内存了,对上面程序的改进如下:
assume cs:code, ds:datasg
datasg segment
db 'file '
db 'file '
db 'file '
db 'file '
db 'file '
db 'file '
datasg ends
code segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 6
s0: mov ds:[400h], cx
mov si, 0
mov cx, 4
s: mov al, [bx+si]
and al, 11011111b
mov [bx+si], al
inc si
loop s
add bx, 10h
mov cx, ds:[400h]
loop s0
mov ax, 4c00h
int 21h
code ends
end start
我们原先是使用寄存器dx来暂存cx中的数值的,现在改用内存空间ds:[400h]来暂存cx的值,就摆脱了寄存器数量的限制
对于上面的程序,我们还有需要改进的地方,使用内存来暂存循环因子寄存器的值肯定是没错的,但是我们应该选择栈作为存储的数据结构,来使得我们的程序条理更加的清楚,每添加一个内层循环,我们就将当前循环因子的值push进栈,每结束一个循环,我们就pop一个值到cx中,这样才是最合理的,改进后的代码如下:
assume cs:code, ds:datasg, ss:stacksg
datasg segment
db 'file '
db 'file '
db 'file '
db 'file '
db 'file '
db 'file '
datasg ends
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
code segment
start: mov ax, datasg
mov ds, ax
mov ax, stacksg
mov ss, ax
mov sp, 10h
mov bx, 0
mov cx, 6
s0: push cx
mov si, 0
mov cx, 4
s: mov al, [bx+si]
and al, 11011111b
mov [bx+si], al
inc si
loop s
add bx, 10h
pop cx
loop s0
mov ax, 4c00h
int 21h
code ends
end start
仅仅是申请一段栈空间,然后把前面的代码中的mov ds:[400h], cx和mov cx, ds:[400h]
改成了push cx和pop cx
,程序就变得清晰了许多