汇编语言:第七章 更灵活定位内存地址的方法

时间:2022-08-08 01:17:11

7.1 and 和 or 指令

  二进制的and or 可以将某位归0或置1

7.2 关于ASCII码

7.3 以字符形式给出数据

  data segment

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

    db 'foRK'       //相当于db 66H,6FH,52H,4BH

  data ends

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

7.4 大小写转换问题

db 'BaSiC'

db 'iNfOrMaTiOn'

如何将第一个字符串转成大写,第二个小写?

我们将ASCII码拿出来对比一下:

大写    十六进制    二进制        小写    十六进制    二进制

A      41      010000001      a      61     01100001

B      42      010000010      b        62      01100010

C      43      010000011      c        63      01100011

.....                        ........

易知:小写字母比大写字母大20H,二进制中即第五位(位从0开始)为1和0

由于我们没有条件判断的指令来+或—20H来改变大小写,所以在这里用and 和 or指令改变二进制第六位数值来达到目的:

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
mov cx,5
s:
mov al,ds:[bx]
and al,11011111B    //第一个循环,前5个内存单元第五位归0  变大写
mov ds:[bx],al
inc bx
loop s

mov cx,11
s2:
mov al,ds:[bx]
or al,00100000B    //第一个循环,后11个内存单元第五位置1 变小写
mov ds:[bx],al
inc bx
loop s2

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

7.5 [bx+idata]

用bx+idata来更灵活的指定偏移地址,也可以写成 idata[bx]很方便的用于表示数组(起始位置在idata,索引在bx)

7.6 用[bx+idata]处理数组

assume cs:code,ds:data          //C语言
data segment
db 'BaSiC'            //char  a[5] = "BaSiC";
db 'MinIX'            // char b[5] = "MinIX";
data ends
code segment
start:
mov ax,data
mov ds,ax
mov bx,0          // int i = 0;
mov cx,5
s:              //do{
mov al,ds:0[bx]
and al,11011111B      // a[bx] = a[bx] & 0xdf
mov ds:[bx],al


mov al,ds:5[bx]
or al,00100000B      //     b[bx] = b[bx] | 0x20
mov ds:5[bx],al
inc bx            // i++;
loop s           //while (i < 5)

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

 7.7 SI 和 DI

SI 和 DI是与BX功能类似的寄存器,但是它们不能拆成两个8位寄存器

相同点:   mov ax,[bx]   mov ax,[si]   mov ax,[di]

     mov ax,[bx+idata]   mov ax,[si+idata]   mov ax,[di+idata]

练习:把 'welcome to masm!' 复制到它下面的内存单元中,利用si,di

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 di,16        //si和di表示数组的2个index变量,放入循环
mov cx,16
s:
mov al,ds:[si]
mov ds:[di],al
inc si
inc di
loop s

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

简化程序;

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,8                //利用idata[si]减少一个index参数
s:
mov ax,ds:[si]
mov ds:16[si],ax
add si,2
loop s

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

 7.8  [bx+si] 和 [bx+di]

mov ax,[bx+si]   =  mov ax,[bx][si]

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

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

实例一:  把每个单词首字母大写

思路:定义一个变量用于循环每一字符串,另一个idata用于定位改字符串第3个位置(即该字符串第一个字母)

assume cs:code,ds:data

data segment        //注意 每个字符串都是16位
db '1. file         '
db '2. edit         '
db '3. search       '
db '4. view         '
db '5. options      '
db '6. help         '
data ends

code segment
start:
mov ax,data
mov ds,ax
mov bx,0
mov cx,6
s:
mov al,ds:[bx+3]
and al,11011111B
mov ds:[bx+3],al
add bx,16
loop s

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

实例二: 把单词变成大写

思路:显然是需要一个嵌套循环,如何处理cx被覆盖?  使用dx暂存外部循环的次数,在内层循环完成时,把dx返回给外层的cx

assume cs:code,ds:data

data segment
db 'ibm             '    
db 'dec             '
db 'dos             '
db 'vax             '
data ends

code segment
start:
mov ax,data
mov ds,ax
mov bx,0
mov cx,4
s0:
mov dx,cx
mov si,0
mov cx,3
s:
mov al,ds:[bx+si]
and al,11011111B
mov ds:[bx+si],al
inc si
loop s
add bx,16
mov cx,dx
loop s0

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

实例二中利用dx保存外部循环计数以便内部循环改变cx之后还能正常使用,但是我们的寄存器数量是很有限的,可以利用内存来存储变量

assume cs:code,ds:data

data segment
db 'ibm             '
db 'dec             '
db 'dos             '
db 'vax             '
dw 0              //定义字型内存单元 用于存储cx值
data ends

code segment
start:
mov ax,data
mov ds,ax
mov bx,0
mov cx,4
s0:
mov ds:[40H],cx
mov si,0
mov cx,3
s:
mov al,ds:[bx+si]
and al,11011111B
mov ds:[bx+si],al
inc si
loop s
add bx,16
mov cx,ds:[40H]
loop s0

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

利用内存的确可以保存变量值,但是这种做法还是比较不方便,实际上一般情况下 需要暂存数据的时候都用栈来保存.

assume cs:code,ds:data,ss:stack

data segment
db 'ibm             '
db 'dec             '
db 'dos             '
db 'vax             '
data ends
stack segment        //定义一个16字节长度的栈
dw 0,0,0,0,0,0,0,0
stack ends  

code segment
start:
mov ax,stack      //栈指针初始化
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax
mov bx,0
mov cx,4
s0:
push cx        //cx值入栈
mov si,0
mov cx,3
s:
mov al,ds:[bx+si]
and al,11011111B
mov ds:[bx+si],al
inc si
loop s
add bx,16
pop cx        //出栈放到cx中
loop s0

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

练习:把data段中每个字符串前4个字母改成大写

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,stack
mov ss,ax
mov sp,16
mov ax,data
mov ds,ax

mov bx,0
mov cx,4
s0:
push cx
mov si,3
mov cx,4
s:
mov al,ds:[bx+si]
and al,11011111B
mov ds:[bx+si],al
inc si
loop s
pop cx
add bx,16
loop s0

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