03.寄存器(内存访问)
寄存器(内存访问)
前言
上一节我们从CPU如何执行指令的角度讲解了8086CPU的逻辑结构,形成物理地址的方法,相关的寄存器,以及一些指令。这一节,我们从访问内存的角度继续学习几个寄存器
内存中字的存储
计算机内部的内存单元是字节单元,即 byte 单元。那我们的 字 是如何存储的呢?字 由两个 字节 组成,其中存储在低地址的称之为 低地址单元,存储在高地址的称之为 高地址单元。例如:0X8005H 中的 0X05H 为低地址单元,0X80H 为高地址单元。我们将字这种这种新的存储单元称之为 字单元。将起始地址为 N 的字单元称之为 N地址字单元
DS 和 [address]
CPU 要读取一个内存单元时,必须要给出内存单元的物理地址,而物理地址又由段基址+偏移地址组成.8086CPU使用DS 寄存器来存储要访问的内存单元的段地址。
那我们要如何使用呢?
前面我们提到的 mov 传送指令可以有两种传送:将 数据 直接送入 寄存器;将 寄存器里的数据 送入 另一个寄存器 。现在又有一种新的使用方法:
将某个内存单元的数据存入寄存器:mov ax, [0]
其中 [...] 中的值表示 偏移地址,而段地址里的值存在 DS 寄存器中, 段寄存器 不支持 mov ds 0020H 的指令,但可以使用 mov ds ax 将一个寄存器的数据传送到另一个寄存器中
字的传送
8086CPU 是16位的架构,可以一次性传送16位的数据,也就是一次性可以传送一个字。
因此,只需要在 mov 使用时指定是 16位的寄存器就行了。例如:
- mov ax, 0001H
- mov [0], bx
- mov cx, [0]
mov add sub 指令
mov add sub 这三条指令,它们都带有两个操作数
mov 指令 可以有以下几种形式:
- mov 寄存器, 数据
- mov 寄存器, 寄存器
- mov 内存单元, 寄存器 反之可行
- mov 段寄存器, 寄存器 反之可行
总之,要遵循一个规律,两个操作数至少有一个可以指定大小
add sub 与 mov 类似,但不能操作段寄存器
数据段
前面讲过,在编程时可以将一段连续的内存单元分为 段 ,存放代码的地方我们称之为 代码段 ,存放数据的地方称之为 数据段
那么如何访问数据段中的数据呢?
我们可以使用上面提到的 DS 和 [address]
栈
学过数据结构的都知道,栈是一种后进先出(LIFO)的数据结构。有出栈和入栈两种操作。
CPU提供的栈机制
8086CPU 提供相关的指令来以栈的形式访问内存空间,这意味着,在基于 8086CPU 编程时,可以将一段内存当作栈使用,并提供了出栈和入栈的指令,最基本的两个指令是 PUSH(入栈)和 POP(出栈)
- push ax --> 将ax中的数据送入栈中
- pop ax --> 将栈顶的取出送入 ax 中
那么存在以下几个问题? - 我们如何知道哪一段内存会被当作栈使用
- 我们如何知道栈顶位置的内存地址
第一个问题是我们程序员来规定把那一块空间当作栈空间
8086CPU 提供了两个寄存器供我们操作栈,段寄存器 SS 和 寄存器 SP,栈顶的段地址存放在 SS 中,栈顶的偏移地址存放在 SP 中,SS:SP 和 CS:IP 采用的一样的计算方式
下面我们来分析以下push 和 pop 两个指令工作时的具体过程
push ax
- sp = sp - 2
- 将寄存器数据存入 SS:SP 中
pop ax
- 先将栈顶SS:SP中的数据存入寄存器ax中
- sp = sp+2
从图中我们可以看出 1000CH ~ 1000F为 栈空间,当栈为空时 栈顶指针指向 1000EH + 2(10010H)处,第一个元素存入 1000EH 处;栈顶 从 高地址 向低地址增长
栈顶超界机制
我们规定一个栈可以存放8个word,栈顶超界有两种情况:
- 当我们存满8个元素时,继续 push 就会将不属于栈的数据覆盖
- 当我们 pop 已经超界,然后又 push,就会将不属于栈的数据覆盖
我们应该如何规避这种情况呢?很遗憾,8086 CPU 并没有提供相关的机制去规避,这需要我们程序员自己在编写程序的过程中,自己去避免这种情况的发生
pop 和 push 指令
- push 寄存器
- push 段寄存器
- push 内存单元
pop 指令与 push 指令类似
栈段
和 代码段 数据段 类似,都是为了方便我们管理我们的程序
段的综述
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元。这完全是我们自己的安排
- 我们可以用一个段来存放数据,称为 数据段
- 我们可以用一个段来存放代码,称为 代码段
- 我们可以用一个段当作栈,称为 栈段
我们可以这样安排,但想要CPU按照我们的安排来访问这些段
- 对于数据段,我们需要把段地址存入 DS 中,[address] 代表偏移地址
- 对于代码段,把段地址放入 CS 中,IP 地址指向我们第一条指令
- 对于栈段,把段地址放入 SS 中,栈顶单元的偏移地址放入 SP 中
可见,不管我们怎么安排,CPU 将内存中的某段内容当作代码,是因 CS:IP 指向了那里,CPU 将某段内存当作栈,是因为 SS:SP 指向了那里,我们一定要清楚,什么是我们的安排,以及如何让 CPU 按照我们的安排工作
参考
<<汇编语言第四版>>-王爽