实模式到保护模式的那一跳

以前看的都是理论,今天拿起《自己动手写操作系统》,把其中的一个小例子改了一个验证自己的理解是否正确

原本是这样的

 1 ; ==========================================
 2 ; pmtest1.asm
 3 ; 编译方法:nasm pmtest1.asm -o pmtest1.com
 4 ; ==========================================
 5 
 6 %include    "pm.inc"    ; 常量, 宏, 以及一些说明
 7 
 8 org    0100h
 9     jmp    LABEL_BEGIN
10 
11 [SECTION .gdt]
12 ; GDT
13 ;                                         段基址,      段界限     , 属性
14 LABEL_GDT:        Descriptor           0,                0, 0             ; 空描述符
15 LABEL_DESC_CODE32:    Descriptor           0, SegCode32Len - 1, DA_C + DA_32    ; 非一致代码段, 32
16 LABEL_DESC_VIDEO:    Descriptor     0B8000h,           0ffffh, DA_DRW        ; 显存首地址
17 ; GDT 结束
18 
19 GdtLen        equ    $ - LABEL_GDT    ; GDT长度
20 GdtPtr        dw    GdtLen - 1    ; GDT界限
21         dd    0        ; GDT基地址
22 
23 ; GDT 选择子
24 SelectorCode32        equ    LABEL_DESC_CODE32    - LABEL_GDT
25 SelectorVideo        equ    LABEL_DESC_VIDEO    - LABEL_GDT
26 ; END of [SECTION .gdt]
27 
28 [SECTION .s16]
29 [BITS    16]
30 LABEL_BEGIN:
31     mov    ax, cs
32     mov    ds, ax
33     mov    es, ax
34     mov    ss, ax
35     mov    sp, 0100h
36 
37     ; 初始化 32 位代码段描述符
38     xor    eax, eax
39     mov    ax, cs
40     shl    eax, 4
41     add    eax, LABEL_SEG_CODE32
42     mov    word [LABEL_DESC_CODE32 + 2], ax
43     shr    eax, 16
44     mov    byte [LABEL_DESC_CODE32 + 4], al
45     mov    byte [LABEL_DESC_CODE32 + 7], ah
46 
47     ; 为加载 GDTR 作准备
48     xor    eax, eax
49     mov    ax, ds
50     shl    eax, 4
51     add    eax, LABEL_GDT        ; eax <- gdt 基地址
52     mov    dword [GdtPtr + 2], eax    ; [GdtPtr + 2] <- gdt 基地址
53 
54     ; 加载 GDTR
55     lgdt    [GdtPtr]
56 
57     ; 关中断
58     cli
59 
60     ; 打开地址线A20
61     in    al, 92h
62     or    al, 00000010b
63     out    92h, al
64 
65     ; 准备切换到保护模式
66     mov    eax, cr0
67     or    eax, 1
68     mov    cr0, eax
69 
70     ; 真正进入保护模式
71     jmp    dword SelectorCode32:0    ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0  处,这一跳在这
72 ; END of [SECTION .s16]
73 
74 
75 [SECTION .s32]; 32 位代码段. 由实模式跳入.
76 [BITS    32]
77 
78 LABEL_SEG_CODE32:
79     mov    ax, SelectorVideo
80     mov    gs, ax            ; 视频段选择子(目的)
81 
82     mov    edi, (80 * 10 + 0) * 2    ; 屏幕第 10 行, 第 0 列。
83     mov    ah, 0Ch            ; 0000: 黑底    1100: 红字
84     mov    al, 'P'
85     mov    [gs:edi], ax
86 
87     ; 到此停止
88     jmp    $
89 
90 SegCode32Len    equ    $ - LABEL_SEG_CODE32
91 ; END of [SECTION .s32]

然后我第一次把代码改成了这样:

  1 ; 编译方法:nasm pmtest1.asm -o pmtest1.com
  2 ; ==========================================
  3 
  4 %include    "pm.inc"    ; 常量, 宏, 以及一些说明
  5 
  6 org    0100h
  7     jmp    LABEL_BEGIN
  8 
  9 [SECTION .gdt]
 10 ; GDT
 11 ;                                         段基址,      段界限     , 属性
 12 LABEL_GDT:        Descriptor           0,                0, 0             ; 空描述符
 13 LABEL_DESC_CODE32:    Descriptor           0, SegCode32Len - 1, DA_C + DA_32    ; 非一致代码段, 32
 14 LABEL_DESC_VIDEO:    Descriptor     0B8000h,           0ffffh, DA_DRW        ; 显存首地址
 15 ; GDT 结束
 16 
 17 GdtLen        equ    $ - LABEL_GDT    ; GDT长度
 18 GdtPtr        dw    GdtLen - 1    ; GDT界限
 19         dd    0        ; GDT基地址
 20 
 21 ; GDT 选择子
 22 SelectorCode32        equ    LABEL_DESC_CODE32    - LABEL_GDT
 23 SelectorVideo        equ    LABEL_DESC_VIDEO    - LABEL_GDT
 24 ; END of [SECTION .gdt]
 25 
 26 
 27 LABEL_SEG_CODE32:
 28     mov ax, SelectorVideo
 29     mov gs, ax          ; 视频段选择子(目的)
 30 
 31     mov edi, (80 * 10 + 0) * 2  ; 屏幕第 10 行, 第 0 列。
 32     mov ah, 0Ch         ; 0000: 黑底    1100: 红字
 33     mov al, 'P'
 34     mov [gs:edi], ax
 35 
 36     ; 到此停止
 37     jmp $
 38     SegCode32Len    equ $ - LABEL_SEG_CODE32
 39 
 40 
 41 
 42 
 43 
 44 
 45 [SECTION .s16]
 46 [BITS    16]
 47 LABEL_BEGIN:
 48     mov    ax, cs
 49     mov    ds, ax
 50     mov    es, ax
 51     mov    ss, ax
 52     mov    sp, 0100h
 53 
 54     ; 初始化 32 位代码段描述符
 55     xor    eax, eax
 56     mov    ax, cs
 57     shl    eax, 4
 58     add    eax, LABEL_SEG_CODE32
 59     mov    word [LABEL_DESC_CODE32 + 2], ax
 60     shr    eax, 16
 61     mov    byte [LABEL_DESC_CODE32 + 4], al
 62     mov    byte [LABEL_DESC_CODE32 + 7], ah
 63 
 64     ; 为加载 GDTR 作准备
 65     xor    eax, eax
 66     mov    ax, ds
 67     shl    eax, 4
 68     add    eax, LABEL_GDT        ; eax <- gdt 基地址
 69     mov    dword [GdtPtr + 2], eax    ; [GdtPtr + 2] <- gdt 基地址
 70 
 71     ; 加载 GDTR
 72     lgdt    [GdtPtr]
 73 
 74     ; 关中断
 75     cli
 76 
 77     ; 打开地址线A20
 78     in    al, 92h
 79     or    al, 00000010b
 80     out    92h, al
 81 
 82     ; 准备切换到保护模式
 83     mov    eax, cr0
 84     or    eax, 1
 85     mov    cr0, eax
 86 
 87     ; 真正进入保护模式
 88     jmp    dword SelectorCode32:0    ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:0 89 ; END of [SECTION .s16]
 90 
 91 
 92 [SECTION .s32]; 32 位代码段. 由实模式跳入.
 93 [BITS    32]

简单来说,就是把LABEL_SEG_CODE32这个段移到了前面,高兴的是编译通的过,遗憾的是运行不了,看了半天,没有想明白那是为什么,我以为我原来的理解有误呢,后来突然看到一个字眼:[SECTION .s32]

                       [BITS  32]

就是这两个东西出的错,这两个是对齐的作用,嗯,在把这两个小东西移到LABEL_SEG_CODE32的前面就可以了

最后是这样的:

 1 ;"t1.asm
 2 ; 编译方法:nasm pmtest1.asm -o pmtest1.com
 3 ; ==========================================
 4 
 5 %include    "pm.inc"    ; 常量, 宏, 以及一些说明
 6 
 7 org    0100h
 8     jmp    LABEL_BEGIN
 9 
10 [SECTION .gdt]
11 ; GDT
12 ;                                         段基址,      段界限     , 属性
13 LABEL_GDT:        Descriptor           0,                0, 0             ; 空描述符
14 LABEL_DESC_CODE32:    Descriptor           0, SegCode32Len - 1, DA_C + DA_32    ; 非一致代码段, 32
15 LABEL_DESC_VIDEO:    Descriptor     0B8000h,           0ffffh, DA_DRW        ; 显存首地址
16 ; GDT 结束
17 
18 GdtLen        equ    $ - LABEL_GDT    ; GDT长度
19 GdtPtr        dw    GdtLen - 1    ; GDT界限
20         dd    0        ; GDT基地址
21 
22 ; GDT 选择子
23 SelectorCode32        equ    LABEL_DESC_CODE32    - LABEL_GDT
24 SelectorVideo        equ    LABEL_DESC_VIDEO    - LABEL_GDT
25 ; END of [SECTION .gdt]
26 
27 [SECTION .s32]; 32 位代码段. 由实模式跳入.
28 [BITS   32]
29 LABEL_SEG_CODE32:
30     mov ax, SelectorVideo
31     mov gs, ax          ; 视频段选择子(目的)
32 
33     mov edi, (80 * 10 + 0) * 2  ; 屏幕第 10 行, 第 0 列。
34     mov ah, 0Ch         ; 0000: 黑底    1100: 红字
35     mov al, 'P'
36     mov [gs:edi], ax
37 
38     ;; 到此停止
39     jmp $
40     SegCode32Len    equ $ - LABEL_SEG_CODE32
41 
42 
43 
44 
45 
46 
47 [SECTION .s16]
48 [BITS    16]
49 LABEL_BEGIN:
50     mov    ax, cs
51     mov    ds, ax
52     mov    es, ax
53     mov    ss, ax
54     mov    sp, 0100h
55 
56     ; 初始化 32 位代码段描述符
57     xor    eax, eax
58     mov    ax, cs
59     shl    eax, 4
60     add    eax, LABEL_SEG_CODE32
61     mov    word [LABEL_DESC_CODE32 + 2], ax
62     shr    eax, 16
63     mov    byte [LABEL_DESC_CODE32 + 4], al
64     mov    byte [LABEL_DESC_CODE32 + 7], ah
65 
66     ; 为加载 GDTR 作准备
67     xor    eax, eax
68     mov    ax, ds
69     shl    eax, 4
70     add    eax, LABEL_GDT        ; eax <- gdt 基地址
71     mov    dword [GdtPtr + 2], eax    ; [GdtPtr + 2] <- gdt 基地址
72 
73     ; 加载 GDTR
74     lgdt    [GdtPtr]
75 
76     ; 关中断
77     cli
78 
79     ; 打开地址线A20
80     in    al, 92h
81     or    al, 00000010b
82     out    92h, al
83 
84     ; 准备切换到保护模式
85     mov    eax, cr0
86     or    eax, 1
87     mov    cr0, eax
88 
89     ; 真正进入保护模式
90     jmp    dword SelectorCode32:0    ; 执行这一句会把 SelectorCode32 装入 cs, 并跳转到 Code32Selector:091 ; END of [SECTION .s16]
92 
93 
94 [SECTION .s32]; 32 位代码段. 由实模式跳入.
95 [BITS    32]

嗯,对齐一定要注意

 
原文地址:https://www.cnblogs.com/cdwodm/p/2886790.html