汇编语言(王爽第三版)实验4 |
您所在的位置:网站首页 › 有第三语言、第四语言吗 › 汇编语言(王爽第三版)实验4 |
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. |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |