zoukankan      html  css  js  c++  java
  • 汇编语言实验四

    实验4  [bx]loop的使用

    1.编程:向内存0:200H~0:23fH依次传送数据0~63(3FH

    程序分析:

    【1】内存0:200H~0:23fH空间与0020:0-0020:3f内存空间是一样的,(这个不会?oh!My God!,物理地址是唯一的,但逻辑地址组合是多种的。)

    【2】因为偏移地址是连续内存单元;我们可以把偏移地址做下文章。bx寄存器存储偏移地址(通过偏移地址的间接访问内存单元,这主要是写入的内存单元)。dx寄存器作为存储中间变量的容器(源数据,常量0-63)来向内存写入。

          汇编代码如下:

    assume cs:code

    code segment

       mov ax,0020H

        mov ds,ax   ;内存单元的段地址写入ds寄存器

        mov bx,0   ;bx寄存器存放偏移地址,初始化为0

        mov dx,0   ;dx寄存器存储常量数值0~63

        mov cx,40H  ;这里40H==64,cx寄存器存放循环次数。也可以为64;

       

    s:  mov [bx],dx ;向[bx]内存单元写入dx值

        inc bx  ;累加bx

        inc dx  ;累加dx

       loop s

     

       mov ax,4c00H

       int 21H

    code ends

    end

    2. 向内存0:200H~0:23fH依次传送数据0~63(3FH),9条命令的程序的简化版本(不包括伪代码):

    程序分析:

    【1】内存0:200H~0:23fH空间与0020:0-0020:3f内存空间是一样的,(这个不会?oh!My God!,物理地址是唯一的,但逻辑地址组合是多种的。)为什么这样?数据0-63是64个连续的数字,0-3fH也是连续的64个编号。我们可以使用一个bx变量就把偏移地址和数字的递增都搞定了!

    修改后的汇编代码如下:

    assume cs:code

    code segment

       mov ax,0020H

        mov ds,ax   ;ds指向0020内存段

        mov bx,0   ;bx寄存器存放偏移地址,初始化为0,也当做源数据:常量数值

        mov cx,64   ;循环次数64

       

    s:  mov [bx],bx ; 向[bx]内存单元写入bx数值

       inc bx

       loop s

     

       mov ax,4c00H

       int 21H

    code ends

    end

    实验体会:

    1. bx寄存器一般用作偏移地址的存储,[bx]也就代表了段地址与[bx]组合后指向的内存单元。    为什么这样,还有一个原因就是在源程序中[xxxx]在masm编译器中当做了常量xxxx,而[bx]则没有这个问题,编译器当做是一个内存地址段的偏移地址。

    2.cx寄存器在循环语句中,常作为计数器使用,loop循环语句把cx寄存器中的值作为判断是否循环的依据。

          CX寄存器在debug调试一个可执行程序时,CX的初始值为该程序的字节尺寸大小。

    3.ds寄存器存放的是指向的内存单元的段地址。

    4.在debug模式下,注意源程序中loop s语句的体现,直接转移到了一个地址(偏移地址)了。

    5.结束debug程序,键入q,退回到dos或命令提示符状态。

    6.在debug状态下,如果想要直接执行的到某个语句,可使用g命令,例如:

          g  XXXX(偏移地址)  在此之前的命令都执行了。

    7.在汇编源程序中,数据不能以字母开头,前面可以加0,例如:0ff02H。

    8.在debug下调试程序,遇到int 21H命令,键入p命令结束程序。

    9.使用p命令可以结束loop的循环(当你遇到了loop语句的时候)。

    10.在写汇编程序时,十进制和十六进制(用h、H标注)可以混用。编译器自动给你转换了。

    程序运行后结果:

    -d ds:0

    0020:0000  00 01 02 03 04 05 06 07-08 09 0A 0B 0C 0D 0E 0F  ................

    0020:0010  10 11 12 13 14 15 16 17-18 19 1A 1B 1C 1D 1E 1F  ................

    0020:0020  20 21 22 23 24 25 26 27-28 29 2A 2B 2C 2D 2E 2F   !"#$%&'()*+,-./

    0020:0030  30 31 32 33 34 35 36 37-38 39 3A 3B 3C 3D 3E 3F  0123456789:;<=>?

    3.下面程序的功能是将mov ax,4c00H之前的指令复制到内存0:200处,补全程序,上机调试,跟踪运行结果:

    程序分析:

    【1】使用debug调试一个EXE文件时候,使用r命令查看寄存器状态,其中cx寄存器的值(初始值)就是该程序代码的大小(按照字节数)。我们可以通过运行debug程序来调试生成的EXE文件,前提你先将CX寄存器赋个值。

          侧面验证CX寄存器的另一个作用。

    【2】cs段寄存器中存储的是指向程序代码段的段地址。此实验是将程序的代码(按字节)复制,故将cs寄存器中的指向代码的段地址赋值给ax,再通过ax寄存器赋值给ds段寄存器。(为什么不能支持从段寄存器cs直接赋值给段寄存器ds呢?回忆下,在8086CPU中,ds、ss、cs、es四个段寄存器存放的都是段地址,在CPU和我们来看。其他的寄存器一般存放的都是数据。

          这4个段寄存器支持从其他寄存器中赋值,但不允许立即数直接赋值给段寄存器。)

    【3】[bx]作为偏移地址为bx的内存单元,它支持的段地址默认是存储在ds段寄存器中的。      本例中ds:[bx]指向的是存储代码段的内存单元(源内存段)。由于ds被占用了,故被写入的内存单元的段地址就没有存储的段寄存器了,es寄存器上场了,es存储了地址为0020H的段地址(目标内存段),那么同样使用[bx]偏移地址的话,必须明确的指出它的前缀,故es:[bx]就指向了内存是0200H的内存单元地址段。

    实验步骤如下:

    (1)首先使用debug调试该程序:假如这个可执行程序(经编译、连接无误后的)为test5.exe

    debug  test5.exe  

    (2)使用r命令显示寄存器状态,显示整个程序代码所占字节数。

    -r

    AX=0000 BX=0000  CX=001C  DX=0000 SP=0000  BP=0000 SI=0000  DI=0000

    DS=0B55 ES=0B55  SS=0B65 CS=0B65 IP=0000   NV UP EI PL NZ NA PO NC

    0B65:0000 8CC8         MOV    AX,CS

    这里我们发现CX= 001CH。

    (3)使用u命令显示汇编指令,求出需要复制的机器码字节数。

    -u cs:0000

    0B65:0000 8CC8         MOV    AX,CS

    0B65:0002 8ED8         MOV    DS,AX

    0B65:0004 B82000       MOV    AX,0020

    0B65:0007 8EC0         MOV    ES,AX

    0B65:0009 BB0000       MOV    BX,0000

    0B65:000C B90300       MOV    CX,0003

    0B65:000F 8A07         MOV    AL,[BX]

    0B65:0011 26           ES:

    0B65:0012 8807         MOV    [BX],AL

    0B65:0014 43           INC    BX

    0B65:0015 E2F8         LOOP   000F

    0B65:0017 B8004C       MOV    AX,4C00

    0B65:001A CD21         INT    21

          我们发现mov ax,4cooH/int 21H它们共占用了5个字节。所以在本实验中我们需要复制的代码字节数是001CH-0005H=0017H==23个字节,故cx计数寄存器赋值为23或17H。

    (4)完整的汇编代码如下:

    assume cs:code

    code segment

        mov ax,cs     ;将cs段地址赋值给ax

        mov ds,ax     ;用cs寄存器中的值初始化ds段寄存器,

       

       mov ax,0020H

        mov es,ax      ;es指向0020H内存段

        mov bx,0      ;偏移地址寄存器清零

        mov cx,17H    ;此处是循环次数:程序机器码的字节数,存储在CX中

     

    s:  mov al,[bx]    ;将[bx]按照字节单元传送给al

        mov es:[bx],al  ;复制到es段内存中

       inc bx

       loop s

       

       mov ax,4c00H

       int 21H

    code ends

    end

    实验结果测试:

    -d 20:0

    0020:0000  8C C8 8E D8 B8 20 00 8E-C0 BB 00 00 B9 17 00 8A  ..... ..........

    0020:0010  07 26 88 07 43 E2 F8 00-00 00 00 00 00 00 00 00  .&..C...........

    ……

    我们发现偏移地址从0000H~0017H存储了程序的执行代码。与程序执行代码存储的内存单元比较,我们发现一样的。

    -d cs:0

    0B65:0000  8C C8 8E D8 B8 20 00 8E-C0 BB 00 00 B9 17 00 8A  ..... ..........

    0B65:0010  07 26 88 07 43 E2 F8 B8-00 4C CD 21 FF 06 48 91  .&..C....L.!..H.

    原创:筑基2017

  • 相关阅读:
    二、编写输出“Hello World”
    实验一:JDK下载与安装、Eclipse下载与使用总结心得
    C++引用
    数组类型与sizeof与指针的引用
    电源已接通,未充电
    改变Web Browser控件IE版本
    “stdafx.h”: No such file or directory
    word2013 blog test
    Editplus配置VC++(1) 及相关注意事项
    VC++6.0在Win7以上系统上Open或Add to Project files崩溃问题 解决新办法
  • 原文地址:https://www.cnblogs.com/kys-mxm/p/12636932.html
Copyright © 2011-2022 走看看