• 第七章 更灵活的定位内存地址的方法 其二


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

    如果我们比较一下前面用到的几种定位内存地址的方法(可称为寻址方式),就可以发现有以下几种方式:

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

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

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

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

    5)[bx+si+idata]用两个变量和一个常量表示地址。

     

     

     

     1 assume cs:codesg,ds:datasg
     2 datasg segment
     3 db 'ibm             '
     4 db 'dec             '
     5 db 'dos             '
     6 db 'vax             '
     7 datasg ends
     8 
     9 codesg segment
    10 start: mov ax,datasg
    11        mov ds,ax
    12        mov bx,0
    13 
    14        mov cx,4
    15    s0: mov si,0
    16        mov cx,3
    17     s: mov al,[bx+si]
    18        and al,11011111b
    19        mov [bx+si],al
    20 
    21        inc si
    22 
    23        loop s
    24 
    25        add bx,16
    26        loop s0
    27 
    28        mov ax,4c00h
    29        int 21h
    30 codesg ends
    31 end start

    这个程序是有错误的,运行之后会进入死循环

    问题在于cx的使用,我们进行二重循环,却只用了一个循环计数器,造成在进行内层的时候覆盖了外层循环的循环计数器。

    多用一个计数器又不可能,因为loop指令默认cx为循环计数器

    怎么办呢?

    我们应该在每次开始内层循环的时候,将外层循环的cx中的数值保存起来,在执行外层循环的loop指令前,再恢复外层循环的cx数值。

    我们可以用寄存器dx来临时保存cx中的值。

     上面的程序用dx来暂时存放cx中的值

    如果在内层循环中,dx寄存器也被使用,该怎么办?

    我么似乎可以使用别的寄存器,但是cpu中的寄存器数量毕竟是有限的,如8086CPU只有14个寄存器。

    在上面的程序中:

    si、cx、ax、bx,显然不能用来暂存cx中的值,因为这些寄存器在循环中也要使用。

    cs、ip、ds也不能用,因为cs:ip时刻指向当前指令,ds也指向datasg段;

    可用的就只有:dx、di、es、ss、sp、bp等寄存器了

    可是如果循环中的程序比较复杂,这些寄存器也都被使用的话,那么该如何?

    我们可以考虑将需要暂存的数据放到内存单元中,需要使用的时候,再从内存单元中恢复。这样我们就需要再开辟一段内存空间。

    程序如下:

     1 assume cs:codesg,ds:datasg
     2 datasg segment
     3     db 'ibm.............'
     4     db 'dec.............'
     5     db 'dos.............'
     6     db 'vax.............'
     7     dw 0            ;定义一个字,用来保存cx
     8 datasg ends
     9 
    10 codesg segment
    11 start:    mov ax,datasg
    12     mov ds,ax
    13 
    14     mov bx,0
    15 
    16     mov cx,4
    17    s0:  mov ds:[40H],cx        ;将外层循环的cx值保存在datasg:40H单元中
    18     mov si,0
    19     mov cx,3        ;cx设置为内存循环的次数
    20     s: mov al,[bx+si]
    21     and al,11011111b
    22     mov [bx+si],al
    23     inc si
    24     loop s
    25 
    26     add bx,16
    27     mov cx,ds:[40H]        ;用datasg:40H单元中的值恢复cx
    28     loop s0            ;外层循环的loop指令将cx中的计数值减 1
    29 
    30     mov ax,4c00h
    31     int 21h
    32 codesg ends
    33 end start

    上面的程序中,用内存单元来保存数据;

    可是上面的做法却有些麻烦,因为如果需要保存多个数据的时候,读者必须要记住数据放到了哪个单元中,这样程序容易混乱。

    一般来说,在需要暂存数据的时候,我们都应该使用栈,栈空间在内存中,采用相关的指令,如:push、pop等,可对其进行特殊的操作。

    改进程序如下:

     1 assume cs:codesg,ds:datasg,ss:stacksg
     2 datasg segment
     3     db 'ibm             '
     4     db 'dec             '
     5     db 'dos             '
     6     db 'vax             '
     7 datasg ends
     8 
     9 stacksg segment            ;定义一个段,用来作栈段,容量为16个字节
    10     dw 0,0,0,0,0,0,0,0
    11 stacksg ends
    12 
    13 codesg segment
    14 start: mov ax,stacksg
    15     mov ss,ax
    16     mov sp,16
    17     mov ax,datasg
    18     mov ds,ax
    19 
    20     mov bx,0
    21 
    22     mov cx,4
    23    s0:  push cx            ;将外层循环的cx值压栈
    24     mov si,0
    25     mov cx,3        ;cx设置为内层循环的次数
    26     s:  mov al,[bx+si]
    27     and al,11011111b
    28     mov [bx+si],al
    29     inc si
    30     loop s
    31 
    32     add bx,16
    33     pop cx            ;从栈顶弹出原cx的值,恢复cx
    34     loop s0            ;外层循环的loop指令将cx中的计数值减 1 
    35 
    36     mov ax,4c00h
    37     int 21h
    38 codesg ends
    39 end start

     1 assume cs:codesg,ds:datasg,ss:stacksg
     2 stacksg segment
     3 dw 0,0,0,0,0,0,0,0
     4 stacksg ends
     5 
     6 datasg segment
     7     db '1. display......'
     8     db '2. brows........'
     9     db '3. replace......'
    10     db '4. modify.......'
    11 datasg ends
    12 
    13 codesg segment
    14 start:    mov ax,stacksg
    15         mov ss,ax
    16         mov sp,16
    17         
    18         mov ax,datasg
    19         mov ds,ax
    20         
    21         mov bx,0
    22         mov cx,4
    23     s:    mov si,0
    24         push cx
    25         mov cx,4
    26         
    27     s0:    mov al,[bx+si+3]
    28         and al,11011111b
    29         mov [bx+si+3],al
    30         inc si
    31         loop s0
    32         
    33         add bx,16
    34         pop cx
    35         loop s
    36         
    37         mov ax,4c00h
    38         int 21h
    39 codesg ends
    40 end start
  • 相关阅读:
    解析三种常见分布式锁的实现
    RabbitMQ基础概念详解
    数据库事务概念
    ECIF与CRM
    MQ(消息队列)学习
    数据粒度的设计
    链表之 头节点与尾指针 区别
    牛客之错题(2016.1.15) && 带头节点与不带头的区别
    数据结构之递归回溯算法
    LeetCode--Single Number
  • 原文地址:https://www.cnblogs.com/fate-/p/12919507.html
Copyright © 2020-2023  润新知