从0创建一个OS (七) 汇编中的段
本节将学习16bit模式的段结构
关键字:段
目标:学习如何在16bit模式下寻址
如果你对段已经很熟悉了,那么你可以跳过本节.
理论基础
在从0创建一个OS (四) 电脑存储的组织形式一节中我们利用org完成了对booot sector的全局基址定义,那是我们第一次在本系列博客中接触到段的概念.
段寄存器中存储的为段地址,从第一代8086机问世以来,之后每一代计算机的基础段寄存器一直没有变化,有以下4个:
cs: code segment 代码段
ds: data segment 数据段
ss: stack segment 栈段
es: extented segment 扩展段
其中ds常和es搭配使用,用于复制字符串.
这4个寄存器无法直接使用类似于mov cs, 0xcd的语句赋值,必须借助于中间寄存器,如:
mov ax, 0xcd mov cs, ax
注意!这4个寄存器在隐式地被CPU调用,用来寻址,所以在改变这4个寄存器的值之前,你必须明白自己在做什么,会不会影响到CPU接下来的寻址.
16bit模式下的物理地址计算方法如下:
物
理
地
址
=
段
地
址
<
<
4
+
偏
移
地
址
物理地址 = 段地址 << 4 + 偏移地址
物理地址=段地址<<4+偏移地址
例如,假设当前的ds的值为0x4d,那么[x20]表示的物理地址为:
0x4d0 + 0x20 = 0x4f0
至于为什么要将段地址左移4位呢?本文不做解释,可以给大家提供一个线索,第一代8086的数据总线有20位.
源码
废话不多说,上代码
注意,这次我们并没有使用
[org 0x7c00]
文件名: boot_sect_segmentation.asm
; ===================================================================== ; 本程序做了4个尝试 ; 1、直接打印标签the_secret指向的值 ; 2、对段寄存器ds赋值0x7C0,隐式调用ds,并打印the_secret指向的值 ; 3、直接显式调用段寄存器es,看看能否使用[es:the_secret]完成对the_secret的打印 ; 4、对段寄存器es赋值0x7C0,显式调用es,并打印the_secret指向的值 ; ===================================================================== mov ah, 0x0e ; 准备使用0x10号中断的打印字符功能 mov al, [the_secret] int 0x10 ; 很明显这样是打印不出来东西的,本系列博客的第二节就尝试过了 ; 给数据段段寄存器赋值,0x7C0,是不是很眼熟? mov bx, 0x7C0 mov ds, bx ; 这里的[the_secret]其实是[ds:the_secret] mov al, [the_secret] int 0x10 ; 显式调用es作为the_secret的段地址存储器 mov al, [es:the_secret] int 0x10 ; 向es赋上我们熟悉的值0x7C0 mov bx, 0x7C0 mov es, bx mov al, [es:the_secret] int 0x10 jmp $ the_secret: db "X" times 510 - ($ - $$) db 0 dw 0xAA55
实验结果
总结
发现尝试2和尝试4打印成功,即隐式调用ds和显式调用es成功,说明CPU在寻址时默认使用的段寄存器为DS.