以前看的都是理论,今天拿起《自己动手写操作系统》,把其中的一个小例子改了一个验证自己的理解是否正确
原本是这样的
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:0 处 91 ; END of [SECTION .s16] 92 93 94 [SECTION .s32]; 32 位代码段. 由实模式跳入. 95 [BITS 32]
嗯,对齐一定要注意