ld462370527 发表于 2014-04-04 09:44

问个简单的关于选择子赋值给段寄存器的问题


; GDT
;                              段基址,       段界限   , 属性
LABEL_GDT:         Descriptor       0,                0, 0         ; 空描述符
LABEL_DESC_CODE32: Descriptor       0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
LABEL_DESC_VIDEO:Descriptor 0B8000h,         0ffffh, DA_DRW             ; 显存首地址
; GDT 结束

GdtLen                equ      $ - LABEL_GDT      ; GDT长度
GdtPtr                dw      GdtLen - 1      ; GDT界限
                dd      0                ; GDT基地址

; GDT 选择子
SelectorCode32                equ      LABEL_DESC_CODE32      - LABEL_GDT
SelectorVideo                equ      LABEL_DESC_VIDEO      - LABEL_GDT
; END of

...

LABEL_SEG_CODE32:
    mov    ax, SelectorVideo
    mov    gs, ax            ; 视频段选择子(目的)

    mov    edi, (80 * 11 + 79) * 2    ; 屏幕第 11 行, 第 79 列。
    mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
    mov    al, 'P'
    mov    , ax

    ; 到此停止
    jmp    $

SegCode32Len    equ    $ - LABEL_SEG_CODE32
; END of 这是看《ORANGES'_自己动手写操作系统》的源码,关于选择子赋值有个小问题
LABEL_SEG_CODE32:
      mov      ax, SelectorVideo
      mov      gs, ax                        ; 视频段选择子(目的)
SelectorVideo这个值是GPT的偏移地址对应到相应的Descriptor宏的结果的地址
Descriptor 0B8000h,         0ffffh, DA_DRW
mov ax, SelectorVideo ;这句ax不应该得到的是下面这个字么,怎么会是显存段地址0B800h呢?
dw      %2 & 0FFFFh                              ; 段界限1
下面是Descriptor宏代码:
; 宏 ------------------------------------------------------------------------------------------------------
;
; 描述符
; usage: Descriptor Base, Limit, Attr
;      Base:dd
;      Limit: dd (low 20 bits available)
;      Attr:dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3
      dw      %2 & 0FFFFh                              ; 段界限1
      dw      %1 & 0FFFFh                              ; 段基址1
      db      (%1 >> 16) & 0FFh                        ; 段基址2
      dw      ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)      ; 属性1 + 段界限2 + 属性2
      db      (%1 >> 24) & 0FFh                        ; 段基址3
%endmacro ; 共 8 字节
感谢~

ld462370527 发表于 2014-04-04 10:02

可不可以这样理解,选择子是一个特殊的数据结构,对CPU来说会自动加载段描述符,将段地址赋给ax?

kkddkkdd11 发表于 2014-04-04 10:19

本帖最后由 kkddkkdd11 于 2014-04-04 10:20 编辑

:-L 这个好多年前看过点,刚刚查了一下

SelectorVideo是选择子
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
这个选择子,只是个偏移,这样赋值之后是,0级,全局

装入gdtr由cpu干这个事,cpu根据偏移量,完成装入段描述符,不知道解释的是否明白:)

ld462370527 发表于 2014-04-04 10:46

回复 3# kkddkkdd11
感谢回复~ :em02:
装入的代码我没贴出来:
GdtLen               equ       $ - LABEL_GDT      ; GDT长度
GdtPtr                dw      GdtLen - 1      ; GDT界限
                         dd         0                ; GDT基地址
        ; 为加载 GDTR 作准备
        xor        eax, eax
        mov        ax, ds
        shl        eax, 4
        add        eax, LABEL_GDT                ; eax <- gdt 基地址
        mov        dword , eax        ; <- gdt 基地址

        ; 加载 GDTR
        lgdt       
加载完了之后,GDT的基地址是0,然后由于选择子的TI,RPL都是0所以SelectorVideo的值刚好是对应描述符相对于GDT的基址偏移。
但是就是不明白为什么
mov ax, SelectorVideo
mov gs, ax;
之后 gs中就是显存的基地址:(

还有个地方就是:
        ; 真正进入保护模式
        jmp        dword SelectorCode32:0        ; 执行这一句会把 SelectorCode32 装入 cs,
                                        ; 并跳转到 Code32Selector:0执行jmp dword SelectorCode32:0; 这句会跳转到LABEL_SEG_CODE32:这个代码段,但是cs是怎么得到这个代码段的段基地址的?求教~
   

ld462370527 发表于 2014-04-04 11:09

回复 3# kkddkkdd11
找到一篇比较好的文章,可以参考下:
http://blog.csdn.net/littlehedgehog/article/details/2089504
   

ld462370527 发表于 2014-04-04 11:37

回复 3# kkddkkdd11
这个应该就是保护模式下的寻址方式吧,具体操作细节应该是CPU自动完成的。感谢~

   

amarant 发表于 2014-04-04 14:50

对于这类问题建议使用一个cpu模拟器调试一下,跑一条执行看看cpu寄存器状态,一目了然

kkddkkdd11 发表于 2014-04-04 15:21

amarant 发表于 2014-04-04 14:50 static/image/common/back.gif
对于这类问题建议使用一个cpu模拟器调试一下,跑一条执行看看cpu寄存器状态,一目了然

有道理,bochs好像可以做这类调试:)

ld462370527 发表于 2014-04-04 15:26

回复 7# amarant
好的,有时间我得试下,感谢大家~:D

rip_world 发表于 2014-05-16 17:25

intel 32位的机器上,像CS,SS这样的段寄存器分为两个部分,可见部分和不可见部分。可见部分就是常说的段寄存器,防止选择子,不可见部分是也称为描述符缓存。
比如当把kernel_cs赋值给cs的时候,这个时候会把GDT中相应的描述符缓存到cs的不可见区域,以此来提升效率。
页: [1]
查看完整版本: 问个简单的关于选择子赋值给段寄存器的问题