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

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

汇编大小写转换

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
assume cs:code,ds:data
data segment
db 'BaSiC' ;把这个字符串全部变为大写
db 'iNfOrMaTiOn' ;把这个字符串全部变为小写
data ends
code segment
start: mov ax,data ;获取数据代码段地址
mov ds,ax ;把代码段地址传送到数据寄存器
mov bx,0 ;初始化基地址寄存器 笔记(ds与bx配合,es与dx配合,cx作为计数器)
mov cx,5
s: mov al,[bx] ;循环体
and al,11011111b ;b是二进制 对al的值进行位与运算取反
mov [bx],al
inc bx
loop s

mov bx,5 ;指向下一个字符串
mov cx,11 ;循环11次

s1: mov al,[bx]
or al,00100000b ;对al的值进行位或运算取反
mov [bx],al
inc bx
loop s1
mov ax,4c00h
int 21
code ends
end start

使用[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
assume cs:code,ds:data
data segment
db 'BaSiC'
db 'MinIX'
data ends
code segment
start: mov ax,data
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 21
code ends
end start

结果

SI AND DI

si和di不能分成2个8位寄存器,也就是不能进行mov al,[si] ,mov al,[di]这样的操作,下面写一个栗子~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
assume cs:codesm,ds:datasg
datasg segment
db 'welcome to masm!'
db '................'
datasg ends

codesm segment
start: mov ax,datasg
mov ds,ax
mov si,0
mov di,16
mov cx,8

s: mov ax,[si]
mov [di],ax
add si,2
add di,2
loop s

mov ax,4c00h
int 21

codesm ends
end start

上面的代码可以看出si,di递增为2 ,循环次数也缩短了一倍,用16位寄存器进行内存单元之间的数据传送一次复制2 个字节,一共循环八次。

再次优化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
assume cs:codesm,ds:datasg
datasg segment
db 'welcome to masm!'
db '................'
datasg ends

codesm segment
start: mov ax,datasg
mov ds,ax
mov si,0
mov cx,8

s: mov ax,[si]
mov [si+16],ax
inc si,2
loop s

mov ax,4c00h
int 21

codesm ends
end start

将字符串头一个字母改为大写

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 '1. file '
db '2. edit '
db '3. search '
db '4. view '
db '5. options '
db '6. help '
datasg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,6
mov si,3

s: mov al,[bx][si]
and al,11011111b
mov [bx][si],al
add bx,16

loop s
mov ax,4c00h
int 21
codesg ends
end start

结果

嵌套循环(把datasg每个单词改为大写)

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
assume cs:codesg,ds:datasg
datasg segment
db 'ibm '
db 'dec '
db 'dos '
db 'vax '
datasg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4 ;外层循环4次
s: mov dx,cx ;因为进行下一次循环不能保存CX利用dx暂存
mov si,0
mov cx,3 ;内层循环3次
s0: mov al,[bx][si]
and al,11011111b
mov [bx][si],al
inc si
loop s0
add bx,16 ;每次内循环完成偏移到下一段字符串
mov cx,dx
loop s
mov ax,4c00h
int 21

codesg ends
end start

讲道理汇编的嵌套循环有点不习惯….
这只是2层嵌套 如果更多嵌套则寄存器不够用,这时候我们就不能用寄存器来暂存CX了

用栈来处理cx缓存问题

将datasg数据段每个单词前4个字幕改为大写

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
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
datasg ends

stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,4

i0: mov ax,[bx]
push cx ;保存外层循环次数
mov cx,2 ;初始化内层循环次数
mov di,0
i1: mov ax,[bx][3][di] ; (ax)=(bx)+(di)+3
and al,11011111b ; 因为di是16位寄存器所以要利用把ax拆开与运算
and ah,11011111b ;这样做的目的是为了减少循环次数
mov [bx][3][di],ax ;把处理后的ax传送到原来的位置
add di,2 ;(di)=(di)+2 di地址偏移2个字单元
loop i1

add bx,16 ;把基地址便宜到下一行字符串
pop cx ;把刚才push的cx出栈

loop i0
mov ax,4c00h
int 21

codesg ends
end start

实验6