内存中字的存储
8086 的寄存器是 16 位的,怎么存储一个字呢?很简单,因为一个字为 2 个字节,那么高 8 位存放高位字节,低 8 位存储低位字节就行了。
内存访问
通过前面的学习,我们知道 mov 指令的基本操作,它可以有一下几种形式:
- mov 寄存器,数据
- mov 寄存器,寄存器
我们怎么把内存中的数据转移到寄存器中呢?猜想应该是 mov 寄存器 内存单元
。内存的表示方法为基址加偏移地址,可以用 [...]
表示偏移地址,那段地址在哪里呢?先来回顾下 8086 是怎么从内存单元中取指令并且执行的,方法为 CS:IP,CS 表示为段寄存器,IP 表示偏移,从中我们联想到要从内存中取数据,段地址应该默认放在某个寄存器中。对的,从内存中取数据的话,段地址默认放在 DS 中,偏移地址由 [...]
给出。知道了表示方法后就可以用 mov 寄存器 内存单元
来取数据了。格式如下:
mov ax [0]
上面这条指令表示的意义为从内存单元 DS:[0] 中取数据放到 ax 寄存器中。DS:[0]
表示的意义为段地址在 DS 中,偏移为 0 。以后就用 DS:[0]
这种方法来表示一个内存单元。能从内存中取数据到寄存器中,当然就可以把寄存器中的数据放到内存中。表示方法如下:
mov [0] ax
表示的意义为把 ax 中的数据放入内存单元 DS:[0] 中。
8086 不允许把数据直接放入段寄存器,要想把数据送入段寄存器,可以先把数据放入通用寄存器,在把通用寄存器的数据放入段寄存器,例子如下:
mov ax,1000H
mov ds,ax
在编写汇编代码时,可以根据需要将一组单元定义为一个段。比如我们用 123B0H ~ 123BAH 这段内存空间来存放数据,则可以认为 123B0H ~ 123BAH 这个段为数据段。其实内存并没被分段,只是人主观的把它视为一个数据段。现在想把 123B0H ~ 123BAH 这个数据段中内容累加,代码如下:
mov ax,123B0H
mov bx,ax
mov al,0
add al,[0]
add al,[2]
add al,[3]
栈
栈是一种先进后出的一种数据结构,在编写汇编代码的时候我们可以将一块内存当做栈来使用。说到栈自然想到栈的两种基本操作,即入栈和出栈。在汇编语言中 push 和 pop 分别表示入栈和出栈。如 push ax 表示把 ax 中的数据送入栈中,pop ax 表示把栈顶取出数据送入 ax 中。这里有一点需要注意:入栈和出栈的操作都是以字为单位的。入栈的时候把数据放入栈顶,出栈的时候从栈顶取出数据。那么 CPU 怎么知道哪段内存是我们定义的栈呢?怎么知道栈顶单元呢?再回想前面的知识,CPU 怎么知道当前要执行的质指令的位置呢?从 CS、IP 指向的段地址和偏移地址中取。那 CPU 怎么从内存单元中取数据呢?从 DS、[xxx] 指向的段地址和偏移地址。那 CPU 怎么知道栈顶单元呢?根据猜想它应该是根据寄存器中应该保存着这些信息。恭喜你又一次答对了,这种举一反三的能力很强,可以奖励自己一个鸡腿当晚餐。栈顶的段地址放在段寄存器 SS 中,偏移地址放在 SP 中。任意时刻,SS:SP 指向栈顶元素。
push 的执行分以下两步:
- SP = SP - 2,SS:SP 指向当前栈顶前面的单元,以当前栈顶前面的栈顶为新的单元
- 将 ax 的内容送入 SS:SP 指向的内存单元处,SS:SP 此时指向新栈顶
pop ax 由以下两步完成
- 将 SS:SP 指向的内存单元处的数据送入 ax
- SP = SP + 2,SS:SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶
当栈满后再向里面 push 数据,或者栈空的时候再次 pop 数据,都将造成栈越界问题,所以写代码的时候要非常的小心保证栈不能越界。
我们可以一块内存当做栈来使用,称为栈段,那么栈段最大是多少呢?这个问题只需要考虑 SP 即可,因为 SP 的范围为 0 ~ FFFFH,所以栈段的最大容量为 64KB。
总结
通过这次学习,知道了字是怎么存储的,即高 8 位存放高位字节,低 8 位存放低位字节;知道了用 DS:[xxx] 的方式访问内存中的数据;知道了栈的概念和它的基本操作 push 和 pop,SS:SP 指向栈顶元素。