zoukankan      html  css  js  c++  java
  • 寄存器与代码段

    汇编语言系列学习笔记:

    在上一篇博文中主要介绍了学习汇编语言的一些必备知识。其中和这篇文章联系比较紧密的是内存地址单元与 CPU 的概念,不熟悉的可以先行阅读上一篇博文。

    在学习寄存器这两章内容的时候,首先要牢记一个观点:指令和数据在内存单元中没有任何区别,它们都是一些二进制信息

    CPU 在读取内存中二进制信息的时候,将有的信息看作指令,有的信息看作数据。

    在接下来的三篇博文中将具体介绍 CPU 到底是根据什么来做出的这种区分的。

    一、寄存器的概念

    寄存器是位于 CPU 内部的一种带有存储性质的器件。寄存器在汇编语言中有着举足轻重的地位,因为程序员可以通过改变寄存器中的内存来实现对 CPU 的控制

    8086CPU 中总有有 14 种不同种类的寄存器,它们分别是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、PSW。

    它们最大能存储 16bit 的数据。

    接下来的几篇文章将逐个的介绍这些寄存器的作用。

    (一)通用寄存器

    8086CPU 中的通用寄存器有下面四种:

    • AX(accumulator):累加寄存器,常用于运算。
    • BX(base):基址寄存器,常用于地址索引。
    • CX(count):计数寄存器。
    • DX(data):数据寄存器,常用于数据传递。

    从上图可知,一个 16 位寄存器可以存储一个 16 位数据。由于 8086CPU 上一代的寄存器都是 8 位的,为了保证兼容性,一个 16 位通用寄存器通常还能当做两个独立的 8 位寄存器使用。

    比如,AX 可以分为 AH 和 AL,见下图:

    AX 的低 8 位(0 位 ~ 7 位)构成了 AL 寄存器,高 8 位(8 位 ~ 15 位)构成了 AH 寄存器。

    8086CPU 可以一次性处理这两种不同长度的数据,分别称为:

    • 字(word):16 位
    • 字节(byte):8 位

    (二)段寄存器和指针寄存器

    8086CPU 中的段寄存器和指针寄存器有下面四种:

    • CS(code segment):代码段寄存器
    • DS(data segment):数据段寄存器
    • SS(stack segment):栈段寄存器
    • ES(extra segment):附加段寄存器
    • IP(instruction pointer):指令指针寄存器
    • SP(stack pointer):栈指针寄存器
    • BP(base pointer):基址指针寄存器

    其中 CS 和 IP 是本文着重要介绍的,其余的将在后面学习到。

    首先想一想 “ 段 ” 这个概念从何而来?这就要从 8086CPU 与内存之间的地址总线宽度说起了。

    8086CPU 的地址总线宽度是 20 位,即一次性可以传送 20 位的地址,理论上能达到 1MB 的寻址能力。但是我们上面介绍的寄存器最高也只有 16 位,无法直接生成 20 位的地址。

    为了不白白的浪费 4 位地址总线,在 8086CPU 中采用一种将两个 16 位地址合成一个 20 位地址的方法。

    如图所示,在 8086 中是通过一个地址加法器来完成的这种转换:物理地址(20 bit) = 段地址(16 bit) × 16 + 偏移地址(16 bit)。其中段地址就存储在段寄存器中。而偏移地址则保存在指针寄存器中。

    这个公式隐含着两个注意点:

    • 因为 段地址 × 16 的大小必然是 16 的倍数,所以一个段内存空间的起始地址必然也是 16 的倍数。
    • 因为偏移地址为 16 位,所以一个段的最大空间只有 216 B = 64 KB。

    这里有一个因果关系要明确:首先是因为 CPU 与内存之间的地址总线的宽度(1MB)高于 CPU 一次性能处理、传输、暂存的最大宽度(64KB),为了不浪费 CPU 的寻址能力,才会有 物理地址(20 bit) = 段地址(16 bit) × 16 + 偏移地址(16bit) 这样的一个转换机制。

    所以我在想,要是做个假设,CPU 中的寄存器都是 20 bit,或者地址总线只有 16 bit 的话,是不是也许就没有段地址这个说法了(这是我个人的思考,如果有不对的地方,烦请指正~)。

    二、代码段

    上面讲了一些比较常用的寄存器,其中 CS 和 IP 寄存器是两个最为关键的寄存器,它们这两个寄存器中的值组合起来 CS:IP 表示了 CPU 当前要读取指令的地址。

    也就是说:在 8086PC 机中,任意时刻,CPU 将 CS:IP 指向的内容当做指令执行。

    为了接下来的讲解,先学习几条会用到的汇编指令:

    • mov ax,4E20H:将 4E20H 这个数送入寄存器 AX。
    • add ax,1406H:将寄存器 AX 中的数值加上 1406H。

    假设现在有下面四条汇编指令:

    • mov ax,0123H
    • mov bx,0003H
    • mov ax,bx
    • add ax,bx

    对应的机器指令为:

    • B8H 23H 01H
    • BBH 03H 00H
    • 89H D8H
    • 01H D8H

    现在的一个编程需要是想让 CPU 顺序执行上面四条指令,可以将这四条指令的机器码存放在一组连续的、起始地址为 16 的倍数的一组内存单元中,如下图:

    这样我们就定义了一个所谓的代码段,这个代码段从内存的第 20000H 号单元开始,存放了 10 字节的指令。

    要想让 CPU 执行这段代码,首先需要将 CS 的内容置为 2000H,IP 的内容置为 0000H。这样 CPU 就从内存单元的 20000H 处开始执行。

    下面以一张动图来演示 CPU 执行第一条指令时 CPU 与内存的信息交互情况:

    (动图演示)

                    

    这张动图清晰的展示了 CPU 是如何执行处于上面内存代码段中的第一条指令(隐藏了很多的细节)。由于指令的执行过程类似,加上制作动图比较耗费时间,就省略了剩余的三条指令的执行过程(- -!)。

    三、总结

    本篇博文首先介绍了 CPU 中的寄存器种类,通过一个地址转换公式引出了两个重要的寄存器 CS 和 IP。有了这两个寄存器的功能做支持,就可以定义一个存放代码的代码段,并让 CPU 去执行这个代码段。

    最后还是引出文章开始的一句话:指令和数据在内存中没有区别,它们都是一些二进制信息,把这些二进制信息看作指令还是数据,是让编程人员通过控制 CPU 中的寄存器来完成的

    (完)

  • 相关阅读:
    2013年工作中用到的10个命令:11-20
    2013年工作中用到的10个命令:11-20
    2013年工作中用到的10个命令:1-10
    OpenJDK源码研究笔记(十):枚举的高级用法,枚举实现接口,竟是别有洞天
    OpenJDK源码研究笔记(十):枚举的高级用法,枚举实现接口,竟是别有洞天
    Java实现 LeetCode 240 搜索二维矩阵 II(二)
    Java实现 LeetCode 239 滑动窗口最大值
    Java实现 LeetCode 239 滑动窗口最大值
    Java实现 LeetCode 239 滑动窗口最大值
    Java实现 LeetCode 238 除自身以外数组的乘积
  • 原文地址:https://www.cnblogs.com/KKSJS/p/9939908.html
Copyright © 2011-2022 走看看