CPU由运算器、控制器、寄存器等器件组成,这些器件靠内部总线相连。
内部总线:CPU内部 <–> 各个器件
外部总线:CPU <–> 主板上其它器件
8086CPU所有的寄存器都是16位的,可以存放两个字节(一个字)。
8086CPU有14个寄存器:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。
AX、BX、CX、DX 通常用来存放一般性数据被称为通用寄存器。
8086上一代CPU(8088)中的寄存器都是8位的。
为保证兼容性,这四个寄存器都可以分为两个独立的8位寄存器(AX --> AH、AL)使用。
AH:高位、AL:低位
1Word(字)= 2Byte(字节)= 16bit(比特)
一个字可以存在一个16位寄存器中,这个字的高位字节和低位字节自然就存在这个寄存器的高8位寄存器和低8位寄存器。
由于一个内存单元可以存放8位数据,CPU中的寄存器又可存放n个8位数据。计算机中的数据大多是由多个8位数据构成的
用十六进制来表示数据可以直观的看出这个数据是由哪些8位数据构成的。
在十六进制表示的数据的后面加 H,在二进制表示的数据后面加 B,十进制表示的数据后面什么也不加
汇编指令不区分大小写
汇编指令 | 高级语言描述 |
---|---|
mov ax,18(后面给前面赋值) | AX = 18 |
add ax,8 | AX = AX + 8 |
丢失进位:进位制不能在8位寄存器中保存,但是CPU不是并真的不丟弃这个进位值
跟mac地址的物理地址不同
CPU访问内存单元时要给出内存单元的地址
所有的内存单元构成的存储空间是一个一维的线性空间 --> 物理地址
16位结构的CPU 特征:
8086有20位地址总线,可传送20位地址,寻址能力为1M( 2 20 = 1 M B 2^{20}=1MB 220=1MB)。但是8086内部为16位结构,它只能传送16位的地址,表现出的寻址能力却只有64k( 2 16 = 64 K B 2^{16}=64KB 216=64KB)
8086CPU采用一种在内部用两个16位地址合成的方法来开成一个20位的物理地址
CPU中的相关部件提供两个16位的地址,一个称为段地址,另一个称为偏移地址
段地址和偏移地址通过内部总线送入一个称为"地址加法器"的部件
地址加法器将两个16位地址合并成一个20位的地址(段地址 x 16 + 偏移地址 = 物理地址)
”段地址×16“ --> 二进制位左移4位
一个数据的二进制形式左移n位,相当于该数据乘上2的n次方
一个数据的n进制形式左移1位,相当于乘以n
内存没有分段
段的划分来自于cpu:由于8086CPU "段地址 x 16 + 偏移地址"的方式给出物理地址,使得我们可以用分段的方式管理内存
编程时可以将若干地址连续的内存看成一个段,用段地址x16定位段的起始地址(基础地址),用段偏移地址定位段中的内存单元
CPU可以用不同的段地址和偏移地址形成一个物理地址
寻址范围:0~FFFFH
段寄存器:提供段地址
8086CPU有四个段寄存器:CS、DS、SS、ES
CS和IP是8086CPU中最关键的寄存器,它指示了CPU当前要读取指令的地址。
CS:代码段寄存器(段地址)
IP:指令指针寄存器(偏移地址)
8086工作过程简要
- 从CS、IP指向内存单元读取指令,读取的指令进入指令缓冲区
- IP = IP + 所读取指令的长度,从而指向下一条指令
转移指令jump:修改CS、IP的值
jump 段地址:偏移地址
jmp:修改寄存器中的值
jmp 某一合法寄存器
代码段:用来存放程序执行代码的一块内存区域
CPU只认被CS:IP指向的内存单元中的内容为指令 --> 将CS:IP指向所定义的代码段中的第一条指令的首地址
任何两个地址连续的内存单元,N号单元和 N+1号单元,可以将它们看成两个内存单元,也可以看成一个地址为N的字单元中的高位字书单元和低位字节单元。
CPU读取内存需要内存单元的地址
8086有一个DS寄存器,用来存放需要读取的内存的地址
mov bx,1000H
mov ds,bx
mov al,[0]
mov al,[0]
:将段地址为ds、内存偏移地址为0的内容放到寄存器
数据 -> 通用寄存器 -> 段寄存器
8086不能直接将数据直接放入段寄存器(
mov ds,1000H
)
=
move 寄存器,数据
move ax, 6
move 寄存器,寄存器
move bx, ax
move 寄存器,内存单元
move ax, [0]
move 内存单元,寄存器
move [0], ax
move 段寄存器,寄存器
move ds, ax
move 寄存器,段寄存器
move ax, ds
+=
add 寄存器,数据
add ax, 6
add 寄存器,寄存器
add bx, ax
add 寄存器,内存单元
add ax, [0]
add 内存单元,寄存器
add [0], ax
-=
sub 寄存器,数据
sub ax, 6
sub 寄存器,寄存器
sub bx, ax
sub 寄存器,内存单元
sub ax, [0]
sub 内存单元,寄存器
sub [0], ax
数据段:将一组长度为N(N≤64K)、地址连续、起始地址为16的倍数的内存单元当作专门存储数据的内存空间
栈特性:FILO(先进后出,后进先出)
两个基本操作:入栈、出栈
push ax
pop ax
8086出栈入栈都以字为单位进行
1、CPU怎么知道的哪里是栈?
2、执行push和pop时候,如何知道那个单元是栈顶单元?8086CPU中,存在段寄存器SS(存放栈顶的段地址)、段寄存器SP(存放栈顶的偏移地址)
任意时刻,SS:SP指向栈顶元素
pop只会移动SS:SP(指针),不会删除之前的值。
栈空时,栈中没有元素,不存在栈顶元素。SS:PP指向栈的最底部的字单元的偏移地址+2。
依靠SS和SP保证能找到栈顶,CPU也不知道栈空间有多大。栈顶可能会超出栈空间。
pop空栈、push满栈 --> 栈顶越界(溢出攻击)
CPU提供记录栈顶上限和下限的寄存器,每次pop和push做检查,但是8086并没有。
栈空间是内存的一部分,只是一段可以以特殊方式访问的内存空间。
栈段:将长度为N(N<=64K)的一组地址连续、起始地址为16的倍数的内存单元,当作栈来使用
栈段只是编程的概念,CPU只认识SS:SP。