19-再谈8086CPU的分段机制

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35733751/article/details/85530683

前面已经简单的讨论过8086CPU的分段机制了,如果已经忘了的同学赶快回去复习一遍(传送门:3-浅谈8086CPU的内存分段机制),在这一篇我们将针对前面的知识进行补充和应用。

8086处理器的工作模式是逻辑上对内存分成各个段(程序员自己抽象),8086处理器在执行指令处理数据时,例如获取下一条指令或者获取某个数据信息,肯定会涉及到寻址,而在8086中一律按照“段地址 x 16 +偏移地址 ”的方式进行。

通常一个标准的8086程序要在操作系统上跑起来,这个程序包含代码段,数据段,附加段和栈段等。换句话说,在8086程序设计中,段与段之间的界限早在程序加载到内存之前就已经准备好了(你可以理解为这相当于一个程序的框架,因为你想要在操作系统上运行起来,就必须遵守操作系统的规则)。

有同学可能会问了,那为啥之前我们写的程序没有各种段呢?

这是因为我们之前编写的汇编程序是基于没有操作系统的环境下跑起来的,也就是说没有操作系统的限制,你想怎么写都行,甚至你可以自己定义规则:在一个程序中定义两个代码段,三个数据段等。

那8086CPU设计程序的时候如何分段呢?先来了解一下Nasm编译器提供的关键字:section(一个伪指令)。但是Nasm编译器并不关心段的用途,也不知道什么是段,CPU也不知道。这些所谓分段都是计算机工程师抽象出来的,方便计算机工程师们编写程序,用来区分程序中的不同内容,如果一个程序的代码段和数据段等都放在一起的话,那写程序的时候就会非常糟糕,所以一切都是为了方便管理。你可以只有一个段,也可以分割成很多个段。但每个段的用途,你自己应该非常清楚,并且给每个段起个有意义的名字,这是必须的。

 

使用section伪指令进行分段,代码如下:

section data1 align=16
db 0x11

section data2 align=16
db 0x22

section data3 align=16
db 0x33

在上述代码中我们定义了三个段,data1、data2、data3分别是这三个段的名称,并且每个段只有一个字节的数据,即0x11、0x22、0x33。align=16是告诉Nasm编译器,这个段的大小为16的倍数,如果不是16的倍数,自动填充0x00凑够成16的倍数为止。

以段data1为例,data1之前没有任何内容,那么段data1的相对起始汇编地址是0,我们知道地址0是以16字节对齐的,因此在段data1中的0x11数据的起始汇编地址就是0x00000。

段data2也是以16字节对齐的,而0x00000的下一个能被16整除的数字只能是0x00010,所以编译器会把0x00010作为段data2的相对起始汇编地址,并在两个段之间填充15字节的0x00。

段data3以此类推,我们可以得出它的起始汇编地址为0x00020。

上述代码被加载到主引导扇区的位置,即内存地址0x07C00,那么:

data1的绝对起始汇编地址就是:0x07C00+0x00000

data2的绝对起始汇编地址就是:0x07C00+0x00010

data3的绝对起始汇编地址就是:0x07C00+0x00020

 

对于每个段都有一个汇编地址,它是相当于整个程序开头(0)的(相对起始汇编地址),为了方便取得该段的汇编地址,Nasm编译器提供了以下伪指令,可以用在你的程序中加section.段名称.start

jmp near Code

section Data1 align=16
AA:
db 0x11

section Data2 align=16
BB:
db 0x22

section Data3 align=16
CC:
db 0x33

;计算每个段的相对起始汇编地址
Code:
mov ax,section.Data1.start
mov ax,section.Data2.start
mov ax,section.Data3.start

 

执行结果:

因为段data1之前有一个jmp指令也会以16字节对齐,所以data1是从0x0010开始的。

猜你喜欢

转载自blog.csdn.net/qq_35733751/article/details/85530683
今日推荐