栈
栈是一种运算受限的线性表,其限定仅在表尾进行插入和删除操作的线性表,表尾也被叫做栈顶。简单概括就是我们对于元素的操作只能够在栈顶进行,也造就了其先进后出的结构特性。
栈 这种内存空间其实本质上有两种操作:将数据放入栈中和在栈中取出数据,相对应的我们管这两种操作叫做入栈和出栈,而栈顶的元素总是最后入栈,需要出栈时又最先被取出的现象我们将其称为LIFO(Last In First Out,后进先出)
栈顶就是一个指针,它永远指向栈中需要最先出栈的元素。
入栈的最基本的指令就是push + 操作数,这里的操作数既可以是存储器或者寄存器的名称,也可以是立即数(通过段地址:偏移地址的形式)。
CPU是通过CS,IP两个寄存器存放的段地址和偏移地址来获取物理地址到存储单元中查找指令数据。CPU针对栈顶应该也有对应的寄存器记录,8086寄存器中有两个寄存器段地址寄存器SS以及偏移地址寄存器SP,栈顶的段地址存放在SS中,偏移地址存放在SP中,PUSH指令与性的时候从SS:SP中获取到栈顶的地址。
PUSH指令的执行过程:
- SS:SP指向当前栈顶前面的单元,以当前单元前面的单元作为新的栈顶。偏移地址改变
- 将指定数据送入SS:SP指向的内存单元处,SS:SP此时指向新的栈顶。
POP指令的格式是POP 寄存器其指令含义就是用一个寄存器来保存出栈的数据,因此POP指令后面不能够加立即数。
栈底
此时我们要拆入一个2字节数据,CPU会将数据放在,我们执行PUSH操作的时候,会将数据首先放入高位存储单元。
高位存储单元: 即物理地址数字更大的单元
特别注意栈顶越界的问题,不仅仅是PUSH操作,也包含POP操作在内。
数据
在汇编语言中,入栈push和出栈pop可以对数据进行操作,这里进行操作的数据有如下的特征
- 数据从寄存器和内存中来
- 数据是字型数据,操作的是16位寄存器或内存中的字型数据
入栈
将16位寄存器或内存中的字型数据放到栈顶标记的上方
修改栈顶标记
出栈
将栈顶标记的字型数据 放到16位寄存器或内存中
修改栈顶标记
从上面我们可以看出,栈顶标记本质是一个内存地址,往栈(连续内存区域中)写入和拿出数据,都是针对相关内存地址进行修改;而在8086CPU中,在任意时刻,将段地址寄存器SS和偏移地址寄存器SP所组合出来的内存地址当作栈顶标记
push
push ax 所做的事情如下
修改SP寄存器中的数值:SP=SP-2
将AX中的字型数据->放到SS:SP所组合的内存地址中,入栈
pop
pop bx
将SS:SP所组合出的内存地址中的字型数据->bx
修改栈顶标记 SP=SP+2,出栈
栈顶越界
当push入栈数据大小或者pop出栈数据大小大于栈顶标记与栈的起始地址所组成的栈空间时,便会发生栈顶越界问题,但汇编语言并不会像其他高级语言那样直接抛出异常和错误
汇编语言在任意时刻,都会将ss:sp所组成的地址认为为栈顶标记
栈的主要作用:临时性地保存数据(临时作用:交换数据)
在call指令和ret指令中,call转移指令临时地将吓一跳指令所在的地址保存了栈中栈顶位置,再通过ret指令从栈顶将保存的指令拿出
寄存器
一个典型的CPU由运算器,控制器,寄存器等器件组成,这些器件靠内部总线相连,内部总线实现CPU内部各个器件之间的联系,而CPU于外设(主板上的其他器件)之间的联系则由外部总线连接
简单来说,在CPU中:
1.运算器进行信息处理;
2.寄存器进行信息存储;
3.控制器控制各个器件进行工作;
4.内部总线连接各个器件,在他们之间进行数据的传送;
寄存器可以用来存储指令和数据。对于一个汇编程序员来说,CPU的主要部件是寄存器。寄存器是CPU中程序可以用指令读写的器件。程序员通过改变各种寄存器中内容来实现对CPU的控制。不同的CPU,寄存器的个数,结构式不同的。
例如:8086CPU有14个寄存器,每个寄存器有一个名字。这些寄存器名字分别是:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,ES,PSW。这些寄存器有着不同的功能,在不同的场合扮演不同的角色。
通用寄存器:AX,BX,CX,DX
8086CPU所有寄存器都是16位的,可以存放两个字节,上述4个寄存器通常用来存放一般性的数据,被称为通用寄存器。
AX可以分为AH,AL,同理,BX又可以分为BH,BL;CX和DX也可以这么拆(H表示hign,L表示low)
AX的低8bits构成AL寄存器,高8bits构成了AH寄存器,AH和AL都是可以独立使用的寄存器。
mov ah,78H(已知该指令是将78H的数据传入ah寄存器中),该语句不会影响AL的值
字节存储
1字节等于8比特位,一个字等于两个字节
比特记为bit,字节记为Byte,字记为word,所以有如下关系:
1Byte=8bits,1word=2Bytes=16bits
而8086CPU出于兼容性的考虑,一次性可以处理两种尺寸的数据:字节以及子数据
一个寄存器可以存储一个字数据
内存单元是字节单元,也就是说一个字节单元对应一个内存单元。当我们要保存一个子数据时,我们应该用两个地址连续的内存单元来保存。数据的低字节存放在低地址单元中,高字节存放在高地址单元中
当CPU操作内存时,内部有如下事件发生:
1)CPU中的相关部件提供了两个16位地址,一个称为段地址,一个称为偏移地址
2)段地址和偏移地址经过内部总线送入地址加法器
3)地址加法器将两个16位地址合成一个20位的物理地址
4)地址加法器将20位的物理地址通过内部总线送入输入输出控制电路
5)输入输出控制电路将20位地址送入地址总线
6)20位物理地址被地址总线送入存储器
地址加法器采用物理地址=段地址*16+偏移地址的方法来合成物理地址,这样一个16位机就可以 访问20位地址,寻址能力也从64KB扩大成1MB
四个段寄存器:CS,DS,SS,ES。当CPU要访问内存时,由他们提供短地址。这里我们看一下CS。
CS和IP是8086CPU中最关键的两个寄存器。他们指示CPU当前要读取的指令的地址。CS称之为代码段寄存器,IP为指令指针寄存器。
在8086CPU中,任意时刻设CS中的值为M,IP中的值为N,则CPU将从M*16+N地址单元中取出一条指令并执行。也就是说,当前执行的指令在哪由CS和IP来决定。可以表示为CS:IP。
参考:http://t.csdnimg.cn/8blus
参考:http://t.csdnimg.cn/BnUQd
参考http://t.csdnimg.cn/nS073