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

以字符形式给出的数据:

使用关键字​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​段内存单元

汇编语言学习笔记2_大小写

实现大小写的转换

观察大小写字母的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分别被改成了大写和小写

汇编语言学习笔记2_大小写_02

下面给出了一种更加灵活的定位内存单元的方法

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

处理前:

汇编语言学习笔记2_寄存器_03

处理后:

汇编语言学习笔记2_ascii码_04

嵌套循环(双层循环)

程序代码:

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

处理前:

汇编语言学习笔记2_大小写_05

处理后:

汇编语言学习笔记2_ascii码_06

注意:​我们这段程序只是两层嵌套,必然需要使用两个循环因子,我们上面的这段程序使用的是寄存器,但是​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​​,程序就变得清晰了许多