# 第七章 更灵活地定位内存地址

第七章 更灵活地定位内存地址

本章主要讲解一些更灵活的定位内存地址的方法和相关的编程方法

  1. and 和 or 指令

    1. and 指令

      • 如:mov al,01100011B
        and al,00111011B
        执行后:
        al=00100011B
      • 通过and指令可将操作对象的相应位设为0,其他位保持不变
        例如al的第6位设为0:and al,10111111B
        例如al的第7位设为0:and al,01111111B
        例如al的第0位设为0:and al,11111110B
    2. or指令,逻辑或运算,按位进行或运算

      • 如:mov al,01100011B
        or al,00111011B
        执行后:
        al=01111011B
      • 通过该指令可将操作对象的相应位设为1,其他位不变
        or al,01000000B;将al的第6位设为1
        or al,10000000B;将al的第7位设为1
        or al,00000001B;将al的第0位设为1
    3. 以字符形式给出的数据

      1. 在汇编程序中,可以使用'×××'的方式指明数据是以字符的形式给出的
        2. 编译器会将它们转化为相应的ASCII码
        3. 例如
        • db 'unIX' ; 相当于:db 75H,6EH,49H,58H
          'u'、'n'、'I'、'X' 的ASCII码分别为75H,6EH,49H,58H
        • mov al,'a' ; 相当于:mov al,61H
          'a'的ASCII码为61H
        1. ASCII码中,大写字母和小写字母之间的规律
          小写字母=大写字母+32
          小写字母=大写字母+20H
          大写字母从41H开始排,小写字母从61H开始排
    4. 大小写转换的问题

      • 方案一:
        1. 识别出是该字节是表示一个的大写英文字符,还是小写的
          用于条件判断的汇编程序,目前还没有学到
        2. 根据+20H 或者 -20H进行大小写转换
      • 方案二:
        1. 若全部转化为大写,则将第5位置0
        and al,11011111B
        2. 若全部转化为小写,则将第5位置1
        or al,00100000B
  2. [bx+常数]
    mov ax,[bx+200]的含义:

    1. 将一个内存单元的内容送入ax,这个内存单元的长度为2字节,存放一个入一个子单元

      该字单元的偏移地址为bx中的数值加上200,段地址在ds中

    2. 也可以写成

      1. mov ax,200[bx]
      2. mov ax,[bx].200
  3. 用[bx+idata]的方式进行数组的处理
    在codesg中填写代码,将datasg中定义的第一个字符串转化为大写,第二个字符串转化为小写

    1. 我们观察datasg段中的两个字符串,一个的起始地址为0,另一个的起始地址为5

    2. 我们可以将这两个字符串看作两个数组,一个从0地址开始存放,另一个从5开始存放

    3. 我们可以用[0+bx]和[5+bx]的方式在同一个循环中定位这两个字符串中的字符

    4. 注意这个数组的定位方式,对比C语言

      C语言的数组定位方式:a[i],b[i], a、b是地址常量

      汇编语言的数组定位方式:0[bx],5[bx]

      所以:[bx+常数]的方式为高级语言实现数组提供了便利的机制

    改进版大小写转换:

    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	;做5次循环
    circ:
    	mov al,[bx]
    	and al,11011111b
    	mov [bx],al
    	mov al,[bx+5];等价于mov al,5[bx];等价于mov al,[bx].5
    	or al,00100000b
    	mov 5[bx],al
    	inc bx
    	loop circ
    	
    	mov ax,4c00h
    	int 21h
    codesg ends
    end start
    
  4. SI和DI

    已经学过的10个寄存器:AX、BX、CX、DX、DS、CS、SS、ES、IP、SP

    1. SI和DI是8086CPU中和bx功能相近的寄存器,bx不够用,所以引进了SI和DI

    2. SI和DI(16位)不能够分成两个8位寄存器来使用【和bx的区别】

    3. 默认段寄存器为ds【和bx的形同】

    4. 下面三组指令也实现了相同的功能

      1. mov bx,0

        mov ax,[bx]

      2. mov si,0

        mov ax,[si]

      3. mov di,0

        mov ax,[di]

      4. mov bx,0

        mov ax,[bx]

      5. mov si,0

        mov ax,[si]

      6. mov di,0

        mov ax,[di]

    5. 用寄存器SI和DI实现将字符串'welcome to masm!'复制到它后面的数据区中

      分析:

      当进行数据处理时,需弄清楚数据存放的位置,也就是数据的内存地址

      通常用ds:si指向要复制的源始字符串

      通常用ds:di指向要复制的目的空间

      注意si、di是16位寄存器,循环中自增时,应该+2

      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
      	
      	mov cx,8
      circ:
      	mov ax,[si]
      	mov [di],ax
      	add si,2
      	add di,2
      	loop circ
      	
      	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
      circ:
      	mov ax,0[si]
      	mov 16[si],ax
      	add si,2
      	loop circ
      	
      	mov ax,4c00h
      	int 21h
      code ends
      end start
      
    6. [bx+si]和[bx+di]

      1. [bx+si]和[bx+di]的含义类似,我们以[bx+si]为例进行讲解

      [bx+si]表示一个内存单元,它的偏移地址为bx中的数值加上si中的数值

      它的段地址在ds中

      1. [bx+si]也可以写成[bx][si]
    7. [bx+si+常数]和[bx+di+常数]

      1. 以[bx+Si+常数]为例讲解

        [bx+si+常量]表示一个内存单元,偏移地址为bx的值+si的值+常数

      2. 指令mov ax,[bx+si+常数]也可以写成如下形式

      3. mov ax,200[bx+si]

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

        1. mov ax,[bx][si].200(数字在后面要加点
    8. 不同的寻址方式的灵活应用

      1. 总结几种定位内存的方法

        1. ds:[常数] 【直接寻址】

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

        1. [bx] 【寄存器间接寻址】

          用一个寄存器的值来表示内存地址,可以间接定位一个内存单元

        2. [bx+常数]

        用一节寄存器的值和常量表示内存地址,可在一个起始地址的基础上用变量间接定位一个内存单元

        1. [bx+si]
      2. [bx+si+常数]

    9. 编程,给定数据段data,将data段中每个单词的头一个字母改写成大写字母

      assume cs:code,ds:data
       data segment
      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
       circ:
       	mov al,[bx+3] # 发现第一个字母都在第三个位置上(从0开始)
       	and al,11011111b
       	mov [bx+3],al
       	add bx,16 # 每个字符串16个字节,每次循环一个字符串
       	loop circ
       	
       	mov ax,4c00h
       	int 21h
       code ends
       end start
      
    10. 编程,给定数据段data,将data段中的每个单词改为大写字母

    11. 【loop指令cx-1之后,在判断是否为0】

    12. 双重循环用汇编怎么实现?

      应该在每次开始内循环的时候,将外层循环的cx的值保存起来,在执行外层循环的loop指令前,在恢复外层循环的cx数值。
    
      可以用寄存器来临时保存,也可以用栈空间(内存)保存【没有多余的寄存器】
    
      更好的方法是使用:栈
    
      * 使用寄存器实现
    
        ```assembly
       assume cs:code,ds:data
        data segment
        ```
    
     	db 4,4,6,4,7,4;单词的字母数
     	 	db '          ';补齐
     	 	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,16
     	 	mov si,0
     	 	mov di,0
     	 	
     	 	mov cx,6;外层循环6次
     	 outer:;外层循环
     	 	mov dx,cx;用寄存器将外层循环的次数保存,C语言中是用栈来保存的
     	 	
     	 	mov cx,0
     	 	mov cl,[di];内循环的次数	
     	 	inner:;内层循环
     	 		mov al,[bx][si+3]
     	 		and al,11011111b
     	 		mov [bx][si+3],al
     	 		inc si
     	 		loop inner
     	 	
     	 	add bx,16
     	 	mov si,0
     	 	inc di
     	 	mov cx,dx;恢复外层循环的次数
     	 	loop outer
     	 	
     	 	mov ax,4c00h
     	 	int 21h
     	 code ends
     	 end start
     	 ```
    
      * 使用栈实现【更好的方法】
    
        ```assembly
       assume cs:code,ds:data,ss:stack
        data segment
        ```
    
     	db 4,4,6,4,7,4;单词的字母数
     	 	db '          ';补齐
     	 	db '1. file         '
     	 	db '2. edit         '
     	 	db '3. search       '
     	 	db '4. view         '
     	 	db '5. options      '
     	 	db '6. help         '
     	 data ends
     	 
     	 stack segment
     	 	dw 1,2,3,4,5,6,7,8
     	 stack ends
     	 
     	 code segment
     	 start:
     	 	mov ax,data
     	 	mov ds,ax
     	 	mov ax,stack
     	 	mov ss,ax
     	 	mov sp,16
     	 	mov bx,16
     	 	mov si,0
     	 	
     	 	mov cx,6;外层循环6次
     	 outer:;外层循环
     	 	push cx;将外层循环的次数保存
     	 	
     	 	mov cx,0
     	 	mov cl,[di];内循环的次数	
     	 	inner:;内层循环
     	 		mov al,[bx][si+3]
     	 		and al,11011111b
     	 		mov [bx][si+3],al
     	 		inc si
     	 		loop inner
     	 	
     	 	add bx,16
     	 	mov si,0
     	 	inc di
     	 	pop cx;恢复外层循环的次数
     	 	loop outer
     	 	
     	 	mov ax,4c00h
     	 	int 21h
     	 code ends
     	 end start
     	 ```
    

    实验

    问题:编程,将datasg段中的每个单词的前4个字母改为大写字母

    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:

    codesg ends

    end start

    
    解:
    
    ```assembly
    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,3
    	mov cx,4
    	outer:
    	push cx # 采用堆栈双重循环
    	mov cx,4
    	inner:
    	mov al,[bx]
    	and al,11011111b
    	mov [bx],al
    	inc bx
    	loop inner
    	add bx,12 # 注意最后一次多加了 1,故需加 16 - 3 - 1 = 12
    	pop cx
    	loop outer
    	
    	mov ax,4c00h
    	int 21h
    	
    codesg ends
    
    end start
    
posted @   三年、  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示