zoukankan      html  css  js  c++  java
  • [BX]和loop指令05 零基础入门学习汇编语言27

    第五章:[BX]和loop指令05

     

    让编程改变世界

    Change the world by program


     

    loop和[bx]的联合应用

     

    考虑这样一个问题:

    计算ffff:0~ffff:b单元中的数据的和,结果存储在dx中。  

    分析:

    (1)运算后的结果是否会超出 dx 所能存储的范围? ffff:0~ffff:b内存单元中的数据是字节型数据,范围在0~255之间,12个这样的数据相加,结果不会大于 65535 ,可以在dx中存放下。 (2)我们是否将 ffff:0~ffff:b中的数据直接累加到dx中? 当然不行,因为ffff:0~ffff:b中的数据是8位的,不能直接加到16位寄存器dx中。 (3)我们能否将ffff:0~ffff:b中的数据累加到dl中,并设置(dh=0,从而实现累加到dx中的目标? 这也不行,因为dl是8位寄存器,能容纳的数据的范围在小 255 之间,ffff : 0~ffff:b中的数据也都是 8 位,如果仅向dl中累加12个 8 位数据,很有可能造成进位丢失。 (4)我们到底怎样将用ffff:0~ffff:b中的8位数据,累加到16位寄存器dx中? 从上面的分析中,我们可以看到,这里面有两个问题:类型的匹配和结果的不超界。   具体的说,就是在做加法的时候,我们有两种方法:

    (dx)=(dx)+内存中的8位数据

    (dl)=(dl)+内存中的8 位数据

    第一种方法中的问题是两个运算对象的类型不匹配,第二种方法中的问题是结果有可能超界。   怎样解决这两个看似矛盾的问题? 目前的方法(在后面的课程中我们还有别的方法)就是我们得用一个16位寄存器来做中介。 我们将内存单元中的 8 位数据赋值到一个16位寄存器ax中,再将ax中的数据加到dx上,从而使两个运算对象的类型匹配并且结果不会超界。   想清楚以上的问题之后,我们编写程序代码。 [codesyntax lang="asm"]
    assume cs:code
    code segment
    	mov ax,0ffffh
    	mov ds,ax	;设置(ds)=0ffffh
    
    	mov dx,0	;初始化累加寄存器,(dx)=0
    
    	mov al,ds:[0]
    	mov ah,0 	;(ax)=((ds)*16+0)=(0ffff0h)
    	add dx,ax	;向dx中加上0ffffh:0单元的数值
    
    	mov al,ds:[1]
    	mov ah,0 	;(ax)=((ds)*16+1)=(0ffff1h)
    	add dx,ax	;向dx中加上0ffffh:1单元的数值
    
    	mov al,ds:[2]
    	mov ah,0 	;(ax)=((ds)*16+2)=(0ffff2h)
    	add dx,ax	;向dx中加上0ffffh:2单元的数值
    
    	mov al,ds:[3]
    	mov ah,0 	;(ax)=((ds)*16+3)=(0ffff3h)
    	add dx,ax	;向dx中加上0ffffh:3单元的数值
    
    	mov al,ds:[4]
    	mov ah,0 	;(ax)=((ds)*16+4)=(0ffff4h)
    	add dx,ax	;向dx中加上0ffffh:4单元的数值
    
    	mov al,ds:[5]
    	mov ah,0 	;(ax)=((ds)*16+5)=(0ffff5h)
    	add dx,ax	;向dx中加上0ffffh:5单元的数值
    
    	mov al,ds:[6]
    	mov ah,0 	;(ax)=((ds)*16+6)=(0ffff6h)
    	add dx,ax	;向dx中加上0ffffh:6单元的数值
    
    	mov al,ds:[7]
    	mov ah,0 	;(ax)=((ds)*16+7)=(0ffff7h)
    	add dx,ax	;向dx中加上0ffffh:7单元的数值
    
    	mov al,ds:[8]
    	mov ah,0 	;(ax)=((ds)*16+8)=(0ffff8h)
    	add dx,ax	;向dx中加上0ffffh:8单元的数值
    
    	mov al,ds:[9]
    	mov ah,0 	;(ax)=((ds)*16+9)=(0ffff9h)
    	add dx,ax	;向dx中加上0ffffh:9单元的数值
    
    	mov al,ds:[0ah]
    	mov ah,0 	;(ax)=((ds)*16+0ah)=(0ffffah)
    	add dx,ax	;向dx中加上0ffffh:0ah单元的数值
    
    	mov al,ds:[0bh]
    	mov ah,0 	;(ax)=((ds)*16+0bh)=(0ffffbh)
    	add dx,ax	;向dx中加上0ffffh:0bh单元的数值
    
    	mov ax,4c00h	;程序返回
    	int 21h
    code ends
    
    end
    [/codesyntax]  

    问题5.4

    应用loop 指令,改进程序5.5 ,使它的指令行数让人能够接受。 请先思考后再看分析。   我们可以看出,在程序中,有12个相似的程序段,我们将它们一般化地描述为:

    mov al,ds:[x]

    mov ah,0

    add dx,ax

    我们可以看到,12个相似的程序段中,只有mov al,ds:[X]指令中的内存单元的偏移地址是不同的,其他都一样。 而这些不同的偏移地址是可在0≤X≤0bH的范围内递增变化的。 我们可以用数学语言来描述这个累加的运算 [caption id="attachment_322" align="aligncenter" width="213"] 用数学语言来描述这个累加的运算[/caption] 从程序实现上,我们将循环做:

    (al)=((ds)*16+X)

    (ah)=0

    (dx)=(dx)+(ax)

    一共循环12次,在循环开始前(dx)=0ffffh,X=0,ds:X指向第一个内存单元。每次循环后,X递增,ds:X指向下一个内存单元。  

    完整的算法描述

    初始化:

    (ds)=0ffffh

    X=0

    (dx)=0

    循环12次:

    (al) =((ds)*16+X)

    (ah) = 0

    (dx)=(dx)+(ax)

    X=X+1

    可见,表示内存单元偏移地址的X应该是一个变量 ,因为在循环的过程中,偏移地址必须能够递增。 这样,在指令中,我们就不能用常量来表示偏移地址。我们可以将偏移地址放到 bx中,用[bx]的方式访问内存单元。 在循环开始前设(bx)=0,每次循环,将bx中的内容加1即可。  

    最后一个问题是,如何实现循环12次?

    我们的loop指令该发挥作用了。 更详细的算法描述。  

    更详细的算法描述初始化

    (ds)=0ffffh

    (bx)=0

    (dx)=0

    (cx)=12

    循环12 次:

    s: (al)=((ds)*16+(bx))

    (ah)=0

    (dx)=(dx)+(ax)

    (bx)=(bx)+1

    loops

    我们的最终程序

    [codesyntax lang="asm"]
    assume cs:code
    
    code segment
    	mov ax,0ffffh
    	mov ds,ax
    	mov bx,0
    
    	mov dx,0
    
    	mov cx,12
    
    s:	mov al,[bx]
    	mov ah,0
    	add dx,ax
    	inc bx
    	loop s
    
    	mov ax,4c00h
    	int 21h
    code ends
    
    end
    [/codesyntax] 在实际编程中,经常会遇到,用同一种方法处理地址连续的内存单元中的数据的问题。 我们需要用循环来解决这类问题,同时我们必须能够在每次循环的时候按照同一种方法来改变要访问的内存单元的地址。 这时,我们就不能用常量来给出内存单元的地址(比如[0]、[1]、[2]中,0、1、2是常量),而应用变量。 “mov al,[bx]”中的 bx就可以看作一个代表内存单元地址的变量,我们可以不写新的指令,仅通过改变bx中的数值,改变指令访问的内存单元。  

    段前缀

    指令“mov ax,[bx]”中,内存单元的偏移地址由bx给出,而段地址默认在ds中。 我们可以在访问内存单元的指令中显式地给出内存单元的段地址所在的段寄存器。 这些出现在访问内存单元的指令中,用于显式地指明内存单元的段地址的“ds:”、“cs:”、“ss:”或“es:”,在汇编语言中称为段前缀。 [buy] 获得所有教学视频、课件、源代码等资源打包 [/buy] [Downlink href='http://kuai.xunlei.com/d/LGYIXMSLZTGK']视频下载[/Downlink]
  • 相关阅读:
    安装和配置nginx
    tomcat 生产发布脚本
    nginx 静态页面访问
    redis 搭建主从
    redis 安装
    perl 操作redis
    mysql 用户除了root一般不建议本地登录
    mysql创建用户
    mysql 查看排序集
    perl 安装Cpan
  • 原文地址:https://www.cnblogs.com/LoveFishC/p/3846984.html
Copyright © 2011-2022 走看看