X86汇编实模式下裸机编程

对于开发者来讲,如果不是做单片机开发,大部分情况下我们写的程序都是跑在操作系统上的,而且也必须依赖操作系统才能运行。但假设我们只有一堆硬件(CPU、内存、硬盘),我们该如何让程序跑起来呢?这就是这篇文章试图解决的问题。

这篇文章不探讨一些基础的问题,比如为什么要有汇编语言?这类问题网上有非常多的文章可以参考。

Intel的8086 CPU将计算机发展的时间轴一分为二,在这之后的CPU几乎都兼容8086指令集。直到现在,64位机器操作系统的启动还是从8086的实模式一步步的切换到64位的长模式,最终才能具备64位的寻址能力。

下面是8086CPU通用寄存器

图1-1 8086通用寄存器

8086CPU有8个16位通用寄存器,其中AX、BX、CX、DX又可以各自拆分成2个8位的寄存器,比如AX就可以拆分成AH和AL,其中AL表示低8位,AH表示高8位。

CPU的实模式主要是指对内存的访问都是访问真实物理地址,这在运行多进程的现代操作系统里基本是行不通的。所以,现在的操作系统都需要将CPU切换到保护模式才能正常工作。

内存的最小单元是字节,8086CPU通用寄存器是16位。所以,CPU访问内存一次操作两个内存单元。如下图:

图1-2 内存和寄存器的关系

上图中,AX寄存器通过16根数据线连接到内存中,由于内存每个单元是1个字节,所以需要两个内存单元才能将AX寄存器填满。

程序如何存放

程序代码会被编译器翻译成机器码加载到内存中,程序运行时,CPU从内存中取出指令依次执行,为了方便指令的读取,一般都将代码和数据分开存放,如下图:

图1-3 代码在内存中如何存放

上图中,0000~0C00所在的内存位置保存了翻译成机器指令的程序代码,0C00开始保存的是程序相关的数据。下面我们来看一个具体的例子,如下:

图1-4 指令运行

图中,0000~0002的位置对应的指令是mov ax, [0C00],表示将0C00位置的数据保存到寄存器ax中。0003~0006的位置是指令add ax, [0C02],表示将0C02位置的值加上ax中的值然后将结果保存在ax中。

程序运行的过程是这样的。首先,指令寄存器IPR指向0000,取出第一条指令,也就是mov  ax, [0C00]。指令执行完后,寄存器的值如下所示:

图1-5

第一条指令执行完之后,IPR指向下一条指令的起始位置,也就是add  ax, [0C002]这条指令。此时寄存AX中的值为3C05。

注意,上面的IPR寄存器里保存的是CPU下一次要执行的指令。

接着,执行第二条指令,如下图:

图1-6

第二条指令执行完,IPR寄存器指向了下一条指令的起始位置。此时寄存器AX中的值就是3C05+8B0F = C714。

上面的程序运行过程太过理想化,回想一下我们平时使用计算机的时候可能同时打开很多个应用程序,这些程序不可能都从起始为0的位置开始,我们将上面的程序稍微做一下改变,如下所示:

图1-7

可以看到,上面程序的指令是从内存位置1000开始的。原来的0C00和0C02现在是在1C00和1C02的位置上了。此时,第一条指令将0C00地址里的数据保存到寄存器AX中,但是0C00所在的位置并不是我们期望的数据,可能是一个非法的数据。

你可能会说了,我们把0C00和0C02改成1C00和1C02不就解决了吗?其实这个也是可以实现的,早期的程序就是这么运行的。但是,仔细想想就会发现这样是有问题的。假如,又有一个程序也要运行,这个时候我们就要将这两个程序的内存给分开,并且要把地址都算好,更糟糕的是每次要安装一个新的程序都需要重新计算。

如果是一两个程序还好,但如果是成百上千个程序要运行,这几乎是一个不可能完成的工作。

所以,编译器都是使用相对地址来寻址,如下所示:

图1-8 相对地址

上面的例子中,一开始IPR从1000开始,表示代码指令开始的位置。DSR从1C00开始,也就是数据的起始位置,仔细观察可以发现,1C00正是0C00+1000的结果。

当执行到下一条指令的时候,DSR就是1C00+2=1C02,这其实就是CPU的相对位置寻址,在现代操作系统的内存管理中也基本上沿用了这种思想。

8086CPU有16根数据线,一次性可以传输2字节数据。而这正好是8086CPU通用寄存器的大小。但是,8086为了能寻址更大的内存,使用了20根地址总线,所以,8086CPU最大可以寻址2^20=1MB。

这就产生问题了,寄存器最大只能保存4字节的数据,远远不能保存1MB的地址数据,如下图所示:

图1-9 20位地址线

由于没有20位的寄存器,所以没办法保存一个完整的地址,于是CPU的设计者们又设计了段寄存器DS和CS,分别表示数据段寄存器和代码段寄存器。如下图:

图1-20 

上图中,每个内存单元的地址都是20位,下面我们来看一下8086CPU是如何通过段寄存器来实现20位的寻址能力的。

想像一下,假如你去上海出差,办完事回家之前要做核酸,但你对上海又不熟悉,你就问酒店的保安大哥哪里有做核酸的。他告诉你,出门往右直走500米,到五角场万达A座,向前100米有一个核酸点,向前200米可以拿核酸结果。

我们将上面的场景套到CPU寻址的场景中,万达A座就相当于基地址,后面核酸点都和

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值