美文网首页汇编语言
寻址方式的灵活运用(问题7.6,7.7,7.9)

寻址方式的灵活运用(问题7.6,7.7,7.9)

作者: 柠檬就是酸 | 来源:发表于2018-09-03 12:19 被阅读0次

    7.6问题

    问题:[bx+idata]的灵活运用

    编程,将datasg段中每个单词的头一个字母改成大写

    assume cs:codesg,ds:datasg
    datasg segment
     db '1\. file       '
     db '2\. edit       '
     db '3\. search     '
     db '4, view       '
     db '5\. option     '
     db '6\. help       '
    datasg ends
    ​
    code segment
     start:......
    codesg ends
    end start 
    

    分析:

    其中定义的字符串在内存中的存放是这样的:

    1.png

    定义了6个字符串,每个长度都是16个字节,需要进行6次循环,用一个变量R定位行,用常量定位列。过程如下:

    • BX先存放第一行的地址

    • mov cx,6 因为总共有六行

    • s:改变第BX行,第3列的字母为大写改变BX的值使它指向下一行的地址。

    • loop

    也就是说,使用bx作变量,定位每行的起始地址,用3定位要修改的列,用[bx+idata]的方式来对目标单元进行寻址

    代码:

    assume cs:codesg,ds:datasg
    datasg segment
     db '1\. file       '
     db '2\. edit       '
     db '3\. search     '
     db '4, view       '
     db '5\. option     '
     db '6\. help       '
    datasg ends
    ​
    code segment
     start: mov ax,datasg
     mov ds,ax
     mov bx,0
    
     mov cx,6
     s:mov al,[bx+3]  ;注意单位是字节,所以是al
     and al,11011111b
     mov [bx+3],al
     add bx,16
     loop s
    
     mov ax,4c00h
     int 21h
    codesg ends
    end start </pre>
    

    7.7问题

    问题:[bx+SI]的灵活运用

    编程,将datasg段中每个单词改写成大写字母

    assume cs:codesg,ds:datasg
    datasg segment
     db 'ibm       '
     db 'dec       '
     db 'dos     '
     db 'vax      '
    datasg ends
    ​
    code segment
     start:......
    codesg ends
    end start
    

    分析:

    其中定义的字符串在内存中的存放是这样的:

    2.png

    在datasg中定义了4个字符串,每个长度为16个字节,因为他们是连续存放的,我们可以将这4个字符串看成一个4行16列的二维数组,按照要求,需要修改每一个单词,即二维数组的每一行的前三列。

    进行4*3次的二重循环,使用R定位行,变量C定位列。外层循环按行来进行,内层循环按列来进行。过程如下:

    • R=第一行的地址

      mov cx,4

      S0:C=第一列的地址

      mov cx,3

      s:改变R行,C列的字母为大写

      C=下一列的地址

      loop s

      R=下一行的地址

      loop s0

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

    代码:

    assume cs:codesg,ds:datasg
    datasg segment
     db 'ibm       '
     db 'dec       '
     db 'dos       '
     db 'vax       '
    datasg ends
    ​
    code segment
     start:mov ax,datasg
     mov ds,ax
     mov bx,0
    
     mov cx,4
     s0: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
     loop s0
    
     mov ax,4c00h
     int 21h
    
    codesg ends
    end start
    

    这段代码,会陷入死循环,原因是cx的使用,程序是二重循环,但是只用了一个循环计数器,造成在进行内层循环的时候覆盖了外层循环的循环计数值。

    在debug这个程序,可以发现是因为cx的错误导致的,但是多用一个计数器又不可能,因为loop指令默认使用cx为循环计数器。所以应该在每次开始内层循环的时候,将外层的cx值保存起来,在执行外层循环的loop指令前,再恢复外层循环的cx数值,可以使用dx来保存。

    改进后的代码:

    assume cs:codesg,ds:datasg
    datasg segment
     db 'ibm       '
     db 'dec       '
     db 'dos       '
     db 'vax       '
    datasg ends
    ​
    code segment
     start:mov ax,datasg
     mov ds,ax
     mov bx,0
    
     mov cx,4
     s0:mov dx,cx          ;使用dx寄存器来临时保存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
     mov cx,dx          ;在这里再恢复cx的值
     loop s0
    
     mov ax,4c00h
     int 21h
    
    codesg ends
    end start 
    

    这个程序使用dx来临时保存cx的值,这是可以的,但是有可能dx这个值在内层循环中也会被使用,在这个程序中,si,cx,ax,bx,显然不能存放cx中的数据,因为这些寄存器在循环中也要使用,cs,ip,ds当然也不能使用,因为cs:ip时刻指向当前指令,ds指向datasg段。

    所以现在讨论的是,程序中经常需要进行数据的暂存,可能是寄存器中的也可能是内存中的,我们应该怎么样做更为合理。

    通用的方案是:使用内存,可以将需要暂存的数据放到内存单元中,需要使用的时候,再从内存单元中恢复,这样就需要开辟一段内存空间。

    再改进后的代码:

    assume cs:codesg,ds:datasg
    datasg segment
     db 'ibm       '
     db 'dec       '
     db 'dos       '
     db 'vax       '
     dw 0          ;定义一个字,用来保存cx
    datasg ends
    ​
    code segment
     start:mov ax,datasg
     mov ds,ax
     mov bx,0
    
     mov cx,4
     s0:mov ds:[40H],cx          ;使用定义的字ds:[40H]来临时保存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
     mov cx,ds:[40H]          ;在这里再恢复cx的值
     loop s0
    
     mov ax,4c00h
     int 21h
    
    codesg ends
    end start 
    

    多定义一个字,也就是说,使用ds:[40H]来存放cx的值。

    但是,上面的方法还是很麻烦,因为如果需要保存多个数据的时候,必须要记住数据存放到了哪个单元,容易混乱,所以更好的方法是使用栈

    最终改进的程序:

    assume cs:codesg,ds:datasg,ss:stacksg
    datasg segment
     db 'ibm       '
     db 'dec       '
     db 'dos       '
     db 'vax       '
     dw 0          ;定义一个字,用来保存cx
    datasg ends
    ​
    stacksg segment
     dw 0,0,0,0,0,0,0,0  ;定义一个栈段,容量为16个字节
    stacksg segment
    ​
    code segment
     start:mov ax,stackag
     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 
    

    7.9问题

    问题:[bx+si+idata]的灵活运用

    编程,将datasg段中每个单词的前四个字母改为大写字母

    assume cs:codesg,ds:datasg,ss:stacksg
    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
    code segment
     start:......
    codesg ends
    end start
    

    分析:

    其中定义的字符串在内存中的存放是这样的: 3.png

    由于数据是连续存放的,可以将这四个字符串看作一个4行16列的二维数组,按照要求,需要修改每个单词的前4个字母,即二维数组的每一行的3~6列。需要进行4*4的二重循环,用变量R定位行,常量3定位每行要修改的起始列,变量C定位相对于起始列的要修改的列,

    首先使用R定位第一行,循环修改R行的3+C列

    然后再用R定位到下一行,再次循环修改R行的3+C列

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

    代码:

    assume cs:codesg,ds:datasg,ss:stacksg
    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
    ​
    code segment
     start:mov ax,stacksg
     mov ss,ax
     mov sp,16          ;让CPU知道和栈段挂钩
     mov ax,datasg
     mov ds,ax          ;让CPU知道和ds挂钩
     mov bx,0
    
     mov cx,4
     s0:push cx          ;用来保存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
    

    相关文章

      网友评论

        本文标题:寻址方式的灵活运用(问题7.6,7.7,7.9)

        本文链接:https://www.haomeiwen.com/subject/hmubwftx.html