汇编语言王爽第四版 实验四(包括对【bx】,loop详解)
本文是对王爽第四版汇编语言第五章的重点知识的详解,最后包含了实验四的答案和解析,希望能够帮助到大家
基本概念
- [bx]与内存单元
[bx]与[0]类似,[0]表示的是内存单元,偏移地址是[0],段地址默认是ds
例子:mov ax,[0] ->将一个内存单元的内容送进ax(内存单元长度为2字节,这主要取决于ax是存放2字节的)
mov al,[0] ->将一个内存单元的内容送进al(内存单元长度为1字节,这主要取决于al是存放1字节的)
上面的段地址都是默认取ds中的,偏移地址取[0]中
mov ax,[bx] ->同上,只不过偏移地址是存放于[bx]中
mov al,[bx] ->同上,只不过偏移地址是存放于[bx]中
- loop
循环的意思,我们在实验一中求2^8就是利用了循环
- 描述性符号"()"
()用来表示一个寄存器或者内存单元的内容
(ax)表示ax的内容,(20000H)表示20000H单元的内容
内存单元的地址都是物理地址
()中的元素可以是1.寄存器名2.段寄存器名3.内存单元的物理地址
不能是例如(2000:0)这样的(段地址:偏移地址的形式),如果想描述可以是((ds)*16+(bx))
- 约定符号idata表示常量
[BX]
mov ax,[bx]
由上面的描述可以知道 指令的意思是(ax) = ((ds) * 16 + (bx)) ->bx是偏移地址,ds是默认的段地址
Loop指令
loop 指令的格式:loop 标号
CPU执行loop指令:1.(cx) = (cx) - 1
2.判断cx的值是否为0,为零就退出循环
框架:
mov cx,循环次数
s:
循环执行的程序段
loop s
其实总的来说跟while(num--){执行程序}循环差不多,num就是循环次数,每次减一,不为零就执行程序
举例:
用加法计算123*236,结果存放在ax中
分析:用加法计算就是讲123加236次
assume cs:code
code segment
mov ax,0
mov cx,236
s:
add ax,123
loop s
mov ax,4c00h
int 21h
code ends
end
在Debug中跟踪用loop指令实现的循环程序
计算ffff:0006单元中的数乘以3,结果存储在dx中
assume cs:code
code segment
mov ax,0ffffh ;汇编数据不能以字母开头,因此加入前缀0
mov ds,ax
mov bx,6
mov al,[bx]
mov ah,0
mov dx,0
mov cx,3 ;设置循环次数
s: add dx,ax
loop s
mov ax, 4c00h
int 21h
code ends
end
按照书本上的一步步走就行了
Debug :g 指令
当我们在Debug中想要追踪某一个特定的程序段,而不想追踪前面的程序段,我们可以使用 g指令
例如:我们想从cs:0012位置开始追踪 -> g 0012
执行上述指令后,从cs:ip位置开始执行到cs:0012位置停止,然后等待你的命令。。。
Debug : p 命令
当我们希望循环一次性的执行完毕我们总不能一直按t吧,可以用p指令进行执行循环
当我们遇到loop指令时使用p指令就可以一次性执行完循环
Debug和masm对指令的不同处理
二者的区别主要是对于【idata】的解释
在Debug中 mov al,[0]表示的是将ds:0中的数据送入到ax中
而在汇编源程序中解释为:将数据0送入到ax中
那么我们在源程序中应该如何ds:0中的内容送到ax中呢?
1.可以用[bx]作为过渡的寄存器
mov ax,2000h
mov ds,ax
mov bx,0
mov al,[bx]
2.在[0]的前面显示的加上段地址
mov ax,2000
mov ds,ax
mov al,ds:[0]
loop和【bx】的联合应用
问题:计算ffff:0 到 ffff:b单元中数据的和,结果存储在dx中
分析:能否直接将ffff:0~ffff:b的数据直接累加呢?不行,因为数据是8位的,不能直接累加到16位的寄存器dx中
能否累加数据到dl中,(dh)设置为0呢?不行,12个8位的数据累加到8位的寄存器可能会造成进位的丢失
解决方法:
1.用一个16位的寄存器作为过渡,然后将16位的数据依次累计到dx中
代码如下:
assume cs:code
code segment
mov ax,0fffffh ;数据首位不能是字母开头,因此前面加上一个前缀0
mov ds,ax
mov bx,0 ;bx代表了偏移地址
mov dx,0
mov cx,12 ;一共循环12次
s: mov al,[bx]
mov ah,0
add dx,ax
inc bx ;bx加1
loop s ;循环
mov ax,4c00h
int 21h
code ends
end
段前缀
就是出现在访问地址单元中,用于显示的指明内存单元的段地址的例如“ds: ” "cs:"等就是段前缀
一段安全的空间
- 我们需要直接向一段内存中写入内容
- 这段内存中不应该存放系统或者其他程序的代码或者是数据
- Dos方式下,一般0:200~0:2ff空间中没有系统或者其他程序的数据和代码
- 向内存中写入内容时,使用0:200~0:2ff这一段空间
段前缀的使用
将内存中ffff:0ffff:b单元中的数据复制到0:200020b(等同于0020:0~0020:b)中
我们循环的将f…中的数据存到dl中(一个字节的单位就行),然后将dl转存到0020:…中
assume cs:code
code segment
mov bx,0
mov cx,12 ;循环12次
S: mov ax,0ffffh
mov ds,ax
mov dl,[bx] ;此时将原内存中的一个单元数据放到了dl中了
mov ax,0020h
mov ds,ax ;更换ds的存储的是目标内存的段地址了
mov [bx],dl ;将dl中的内容转存到目标内存中
inc bx ;bx指针加一
loop s
code ends
end
可以再加一个段前缀使得代码更加的简洁
assume cs:code
code segment
mov ax,0ffffh
mov ds,ax
mov ax,0200h
mov es,ax
mov bx,0
mov cx,12
s: mov dl,[bx] ;将ds:bx中的存到dl中
mov es:[bx],dl
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
实验四:【bx】和 loop的使用
-
向内存0:200~0:23F 依次传送数据 0~63(3FH)
分析一哈:跟上面的问题类似,我们一共需要传送64次数据(从0 - 63) 每次用8位的寄存器进行中转就行了
😃
assume cs:code
code segment
mov ax,0
mov ds,ax ;段数据是0
mov cx,64 ;64次循环
mov bx,200h
mov al,0
s: mov [bx],al
inc bx ;bx加一
inc al ;数值加一
loop s
mov ax,4c00h
int 21h
code ends
end
我们编译链接执行后debug看一下0:200的内存
发现内存的确是从0-63(0-3F)进行填充,不熟悉编译链接debug的可以查看我上一篇文章,有详细的步骤
- 向内存0:2000:23F依次传入数据063(0~3FH),程序中只能用9条指令,包括mov ax,4c00h和int 21h
assume cs:code
code segment
mov bx,0h
mov ds,bx
mov ax,200h
mov cx,64
s: mov [bx+200h],bx
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
结果不再演示了,你可以自己debug看一下
-
补全下面的程序,其功能是将
mov ax,4c00
之前的指令复制到内存0:200处,补全程序,上机调试,跟踪运行结果提示:
- 复制了什么?从哪里到哪里?
- 复制的是什么?有多少字节,你如何知道要复制的字节数量?
我们复制的是指令,指令存放在cs:ip中,所以第一个空应该填cs
第二个空填写17,可以在执行前查看一下占用的字节数
assume cs:code
code segment
mov ax,cs
mov ds,ax
mov ax,0020h
mov es,ax
mov bx,0
mov cx,23
s: mov al,[bx]
mov es:[bx],al
inc bx
loop s
mov ax,4c00h
int 21h
code ends
end
我们执行完毕之后,用debug查看一下
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)