要知道,内存空间时不能随意随意读写的,因为可能会触及操作系统内存,这就是“不安全”的做法,是一次不合法的行为
在这之前,先说另一个知识点:
段前缀:我们可以通过“段前缀”指令来认为更改默认的段寄存器
例如:mov AX, [0]
和mov AX, DS:[0]
是等价的(默认为DS)
我们可以这样显式的指定我们要的段地址:
mov AX, ES:[0]
:段地址在ES中,偏移地址为0
对于8086CPU,段地址寄存器有DS、CS、ES、SS
永远记住,我们是在操作系统的环境中工作,操作系统管理所有的资源,当然也包括内存,如果我们需要向内存空间写入数据的话,要使用操作系统给我们分配的空间,而不应直接使用任意指定的内存单元向里面写数据
同样记住,我在学习汇编语言,要使用它来获得底层的编程体验,理解计算机底层的基本工作原理,所以我们要尽量直接对硬件编程而不去理会操作系统
在纯DOS(实模式)下,可以不理会DOS而直接使用汇编语言去操作真实的硬件,因为运行在CPU实模式下的ODS没有能力对硬件系统进行全面、严格地管理;但是在Windows 2000、Unix这些运行于CPU保护模式下的操作系统中,是无法忽视操作系统的存在的,硬件已经被这些操作系统利用CPU保护模式所提供的功能全面而严格地管理了
一段安全的空间:在一般的PC机中,DOS方式下,DOS和其它合法的程序一般都不会使用0:200~0:2ff
的256
个字节空间,所以这段空间是安全的
(至于为啥这256个字节空间是安全的,以后再讲~)
So……以后当我们需要直接向一段内存中写入一段内容时,就使用00200H~002FFH
这段空间
举个栗子如何:^ - ^
谜面:请将内存fff:0~fff:b单元中的数据拷贝到0:200~0:20b单元中(汇编实现)
分析:将目标地址0:200~0:20b看成0020:0~0020:b,和源地址单元的偏移地址从同一数值开始(减少寄存器的使用)
谜底:
assume CS:code
code segment
mov BX, 0 ;(BX)=0偏移地址从0开始
mov CX, 12 ;(CX)=12,循环12次
s:mov AX, 0FFFH ;为DS赋值做准备
mov DS, AX ;(DS)=0FFFH,准备从“源段”读取数据
mov DL, [BX] ;(DL)=((DS)*16+(BX)),将FFFF:BX中的数据送入DL
mov AX, 0020H ;为DS赋值做准备
mov DS, AX ;(DS)=0020H,准备向“目标段”传送数据
mov [BX], DL ;((DS)*16+(BX))=(DL),将源数据送入目标单元
inc BX ;(BX)=(BX)+1
loop s
mov AX, 4C00H
int 21H
code ends
end
上面因为源单元FFFF:X和目标单元0020:X相距大于64K(一个段的最大长度)所以每次循环要用两次即设置两次DS的值(现从源地址获取数据,再往目标地址写入数据)
BUT!上面的做法效率不高,可以使用不同的段地址寄存器!
改进版的谜底:
assume CS: code
code segment
mov AX, 0FFFFH ;看吧
mov DS, AX ;这四行
mov AX, 0020H ;分别使用两个不同的段寄存器
mov ES, AX ;DS和ES(转下)
mov BX, 0
mov CX, 12
s:mov DL, [BX] ;于是每次循环
mov ES:[BX], DL ;显示的指定前缀(因为不是默认的DS)
inc BX
loop s ;只需要改变偏移地址(BX),而不需要改变段地址的值了
mov AX, 4C00H
int 21H
code ends
end