汇编语言(王爽)-更灵活的定位内存地址的方法


and和or指令

and指令

逻辑与指令,按位进行与运算

0为假,1为真

双方为真,才为真

通过该指令可将操作对象的相应位设为0,其他位不变

or指令

逻辑或指令,按位进行或运算

一方为真,即为真

通过该指令可将操作对象的相应位设为1,其他位不变


关于ASCII码

所谓编码方案,就是一套规则,它约定了用什么样的信息来表示现实对象

将人能理解的信息存储在计算机中,要对其进行编码,将其转换为二进制信息进行存储。而计算机要将这些存储的信息再显示给人看,就要再对其进行解码。只要编码和解码采用相同的规则,就可以将人能理解的信息存入计算机,再从计算机中取出


以字符形式给出的数据

汇编语言中,用' '的方式指明数据是以字符的形式给出的,编译器将它们转化为对应的ASCII

如:

db 'unIX'相当于db 75H,6EH,49H,58H

mov al,'a'相当于mov al,61H


大小写转换问题

BaSiC转换为全大写,将iNfOrMaTiOn转换为全小写

小写字母的ASCII码值比大写字母的ASCII码值大20H

ASCII码的二进制形式来看,除第5位外,大写字母与小写字母的其他各位都一样。大写字母ASCII码第5位为0,小写字母ASCII码第5位为1

1.png

新方法,一个字母,不管它原来是大写或者小写,将它第5位置0,将变为大写字母;将它的第5位置1,将变为小写字母,则不需要在处理前判断字母的大小写

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 'BaSiC'
db 'iNfOrMaTiOn'
datasg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0
mov cx,5 ;5个字母,循环5次
s: mov al,[bx]
and al,11011111B ;and指令,将ASCII码第5位置0,变为大写字母
mov [bx],al ;将变换后的ASCII码写回原内存单元
inc bx
loop s

mov bx,5 ;设置ds:bx指向'iNfOrMaTiOn'第一个字母
mov cx,11 ;11个字母,循环11次
s0: mov al,[bx]
or al,00100000B ;or指令,将ASCII码第5位置为1,变为小写字母
mov [bx],al ;将变换后的ASCII码写回原内存单元
inc bx
loop s0

mov ax,4c00h
int 21h
codesg ends
end start

[bx+idata]

[bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata

指令mov ax,[bx+200]含义:

将一个字单元的内存单元内容送入ax,段地址在ds中,偏移地址为bx中的数值加200

数学化描述为:(ax)=((ds)*16+(bx)+200)

该指令常用格式:

  1. mov ax,[200+bx]

  2. mov ax,200[bx]

  3. mov ax,[bx].200


用[bx+idata]的方式进行数组的处理

将第一个字符串转换为大写,将第二个字符串转换为小写

将两个字符串看作是两个数组,一个从0地址开始存放,另一个从5开始存放,可以用[0+bx][5+bx]的方式在同一个循环中定位这两个字符串中的字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'MinIX'
datasg ends

codesg 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
codesg ends
end start

SI和DI

SIDI8086CPU中和bx功能相近的寄存器

SIDI不能分成两个8位的寄存器来使用

SIDI实现将字符串welcome to masm!复制到它后面的数据区中

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:codesg,ds:datasg
datasg segment
db 'welcome to masm!'
db '................'
datasg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov si,0 ;ds:si指向原始字符串
mov di,16 ;ds:di指向目的空间

mov cx,8 ;用16位寄存器进行内存单元之间的数据传送,一次复制2个字节,共循环8次
s: mov ax,[si]
mov [di],ax
add si,2 ;一次复制2个字节,所以一次循环后加2
add di,2
loop s

mov ax,4c00h
int 21h
codesg ends
end start

使用[bx(si或di)+idata]方式,使程序更简洁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
codesg segment 
start: mov ax,datasg
mov ds,ax
mov si,0

mov cx,8
s: mov ax,0[si]
mov 16[si],ax
add si,2
loop s

mov ax,4c00h
int 21h
codesg ends
end start

[bx+si]和[bx+di]

[bx+si][bx+di]的含义相似

[bx+si]表示一个内存单元,偏移地址为(bx)+(si)

指令mov ax,[bx+si]含义:

将一个字单元的内存单元的内容送入ax,段地址在ds中,偏移地址为bx中的值加上si中的值

数学化的描述为:(ax)=((ds)*16+(bx)+(si))

该指令常用格式:

mov ax,[bx][si]


[bx+si+idata]和[bx+di+idata]

[bx+si+idata][bx+di+idata]的含义相似

[bx+si+idata]表示一个内存单元,偏移地址为(bx)+(si)+idata

指令mov ax,[bx+si+idata]含义:

将一个字单元的内存单元的内容送入ax,段地址在ds中,偏移地址为bx中的数值加上si中的数值再加上idata

数学化的描述为:(ax)=((ds)*16+(bx)+(si)+idata)

该指令常用格式:

  1. mov ax,[bx+200+si]

  2. mov ax,[200+bx+si]

  3. mov ax,200[bx][si]

  4. mov ax,[bx].200[si]

  5. mov ax,[bx][si].200


不同的寻址方式的灵活应用

  1. [idata]用一个常量来表示地址,可用于直接定位一个内存单元

  2. [bx]用一个变量来表示内存地址,可用于间接定位一个内存单元

  3. [bx+idata]用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元

  4. [bx+si]用两个变量表示地址

  5. [bx+si+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:codesg,ds:datasg
datasg segment
db '1. file ' ;定义字符串长度为16个字节
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
s: mov al,[bx+3]
and al,11011111b
mov [bx+3],al
add bx,16
loop s
codesg ends
end start

2.png

将每个单词改为大写字母

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
39
assume cs:codesg,ds:datasg,ss:stacksg
datasg segment
db 'ibm ' ;定义字符串长度为16个字节
db 'dec '
db 'dos '
db 'vax '
datasg ends

stacksg segment ;定义一个栈段,容量为16个字节
dw 0,0,0,0,0,0,0,0
stacksg ends

codesg segment
start: mov ax,stacksg
mov ss,ax
mov sp,16
mov ax,datasg
mov ds,ax
mov bx,0

mov cx,4
s0: push cx ;外循环cx入栈,保存外循环次数
mov si,0
mov cx,3 ;开始内循环

s: mov al,[bx+si]
and al,11011111b ;对行内每列字母转换大写
mov [bx+si],al ;转换完成后写回原内存单元
inc si
loop s

add bx,16 ;切换到第二行继续转换
pop cx ;外循环cx出栈,继续外循环
loop s0

mov ax,4c00h
int 21h
codesg ends
end start

3.png

当进行二重循环时,只有cx一个循环计数器,在进行内层循环时,会覆盖外层循环的循环计数值

  1. 无法多使用一个计数器,因为loop指令默认cx为循环计数器

  2. 使用寄存器来暂存cx中的值,但CPU中寄存器的数量是有限的,可用的寄存器有:dxdiesssspbp,若循环中程序比较复杂,这些寄存器可能也会被使用

  3. 使用内存单元来暂存cx中的值,但如果需要保存多个数据时,必须记住数据存放在哪个内存单元中,这样程序容易混乱

  4. 一般来说,在需要暂存数据的时候,我们都应该使用栈

将每个单词的前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
39
40
41
42
43
assume cs:codesg,ss:stacksg,ds:datasg

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

datasg segment
db '1. display '
db '2. brows '
db '3. replace '
db '4. modify '
datasg ends

codesg segment
start: mov ax,datasg
mov ds,ax
mov bx,0 ;定位行

mov ax,stacksg
mov ss,ax
mov sp,16

mov cx,4
s0: push cx
mov si,0
mov cx,4

s: mov al,[bx+si+3]
and al,11011111b
mov [bx+si+3],al
inc si
loop s

add bx,16
pop cx
loop s0

mov ax,4c00h
int 21h

codesg ends

end start

4.png

bx来作变量,定位每行的起始地址,用si定位要修改的列,用[bx+si+3]来对目标单元进行寻址

---------------The End---------------
0%