内存中字的储存
在8086CPU中,寄存器为16位,可以储存一个字(1Word=2Byte),拿ax来说,低8位放在al中,高8位放在ah中。
在内存单元一个内存单元只能存储一个字节,那么如果存储一个字型数据就会用到两个内存单元,低8位放在低地址当中,高8位放在高地址当中,比如下图中,储存了两个字型数据,一个是4E20H,一个是0012H,它们的存放数据大概如下:
而当连续两个内存单元储存的是一个字型数据的时候,可以将这字型数据的起始地址称为N地址字单元,比如00001内存单元和00002内存单元,可以直接称为00001地址字单元。
数据的读写
在第二章中写到如何操作CPU的执行指令,让内存中的数据当作指令还是数据都取决于程序员,当CS和IP指向的地址则当作指令执行,那读取数据也需要由段地址和偏移地址组成。
8086CPU中,数据地址的段地址由段寄存器DS来指定,并且不能直接将数据送入DS段寄存器,只能通过其他寄存器来传送给段寄存器DS(这是8086CPU的硬件设计,只需要知道就可以了),那偏移地址呢?
先来看看下面的代码,下面的代码是通过ax寄存器把内存单元2000H段地址传送给DS,然后读取内存单元2000段中的0001单元:
mov bx,2000H
mov ds,bx
mov al,[0001H]
偏移地址是由程序员手动输入的,当编译器看见[]
的时候,会自动把段寄存器DS中的值与[]
号中数据进行合成为一个20位的物理地址,然后读取这个物理地址中的数据。
那么如何把寄存器中的数据写入内存中呢?只需要将两个位置相关换一下,就可以了,比如下面代码,把ax的低位寄存器al中的12H数据写入内存2000段中的0001单元。
mov bx,2000H
mov ds,bx
mov al,12H
mov [0001H],al
字型数据传送
8086CPU是16位架构,那么意味着一次性可以传输16位数据,上面操作的都是8位数据,也可以传输16位数据,只需要给出16位寄存器的名字就可以传送了,但是16位寄存器分两个内存单元储存,一个内存单元只能储存8位数据,比如储存一个8E20H数据到2000:0000内存单元中,那么20H储存在2000:0000中,而8E储存在2000:0001中。
CPU提供的栈以及机制
栈是一种特殊方式访问的内存单元,那么它有什么用呢?以后会慢慢来说到,在这里只是先对栈空间有一个大概的认识,栈的特殊性在于后进先出,英文缩写为LIFO(Last in First Out)。
这个是什么意思呢?可以把栈看作一个放书的盒子,依次放3本书进去的时候,需要取出放进去的第一本书的时候,就会先把上面的两本书依次拿出来,才能取到放进去的第一本书。
当需要取出哪一本书的时候,我们总会先拿出最上面的那一本书,不然无法拿到需要的书,而每取出一本书,下一本总是在最上面。
在程序化的角度上来说是应该有一个标记,这个标记中指向最上面的书,也就是栈顶,如下图所示:
现今的CPU中都有栈的设计,包含8086,既然有栈的设计,肯定也有对栈访问的指令,其中最基本的就是PUSH(入栈)和POP(出栈),比如push ax代表将ax寄存器的数据送入栈中,入栈和出栈都是字型数据操作,比如下图是一个操作栈的例子:
虽然说现在可以操作栈了,但是有两个疑问:
- 栈中的数据存储在哪里?
- 上面说到,有一个标记,总是指向栈顶,那这个栈顶在哪里?
上面两个问题可以归于一个,其实栈也是在内存单元中,只是它是一段特殊访问方式的空间,那既然是内存单元,那可能也有类似与段寄存器和偏移寄存器这样的寄存器来指向栈,它们就是SS:SP。
SS存放栈的段地址,而SP存放栈的偏移地址,SS:SP在任意时刻指向的是栈顶,我们可以通过修改SS和SP来指定哪一段内存单元为栈,那么现在就可以很好的解释push和pop指令的工作方式,比如push ax的执行,由以下两部分完成:
- SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶起前面的单元为新栈顶。
- 将ax中的内容送入SS:SP指向的内存单元处,SS:SP此时指向新栈顶。
上面的步骤可以用下图来表示:
从图中可以看出,8086CPU中,入栈时,由栈顶高地址向低地址增长,而出栈就是由低地址到高地址增长。
栈顶超界
可以想象一下,当栈空间为2000H:0000H-2000H:000FH的16个内存单元时,那么当栈为空,栈顶在0010H位置,如果这时我们操作出栈,那么SP应该+2,即为0012H,那如果入栈低于了20000H这个内存空间的时候呢?这两种情况都超出了栈的范围,就会覆盖相应的内存单元的数据,比如在下面两个图中,分别对出栈和入栈都演示了一个超界的情况:
在内存单元中,可能存放数据,代码,也有可能存放其他应用的数据代码等,如果超出了就会出现其他未知的问题,在8086CPU中,并没有什么机制来预防这样的问题,应为8086CPU只需要关注栈顶在哪里,并不会关注栈的空间有多大,所以我们需要特别注意,这是非常危险的一个操作。
《汇编语言学习笔记(四):寄存器[内存访问]》留言数:0