前两天把第五章基本看完了,刚开始看的时候头脑很乱,作者把整个工程分成了好几个目录,又拆了好几个头文件。这样做无疑是非常正确的,如果把所有的代码都堆在一起,不但改起来难找,而且改一个模块的话就要整个工程重新编译链接。但对于初学者来说一开始还难以适应这种方式,尤其是汇编跟C的代码互相调来调去,容易看花眼。而且分成多个文件的话,必须写MAKEFILE来编译,要不然会吐血的。
适应总是要有一个过程的,我就想一开始用汇编写完整个第五章的要求,然后看看有哪些模块是必须用汇编写的,哪些模块是可以用C写的,汇编毕竟晦涩难懂,远远没有C来得畅快。下面就祭上堆栈,GDT切换纯汇编版:
;编译链接方法
;nasm -f elf -o kernel.o kernel.asm
;ld -s -Ttext 0x30400 -o kernel.bin kernel.o
%include "pm.inc"
[section .data]
LABEL_DESC_GDT: Descriptor 0,0,0
LABEL_DESC_FLAT_RW: Descriptor 0,0ffffh,DA_DRW + DA_32 + DA_LIMIT_4K
LABEL_DESC_FLAT_C: Descriptor 0,0ffffh,DA_CR + DA_32 + DA_LIMIT_4K
LABEL_DESC_VIDEO: Descriptor 0b8000h,0ffffh,DA_DRW
Selector_Flat_RW equ LABEL_DESC_FLAT_RW - LABEL_DESC_GDT
Selector_Flat_C equ LABEL_DESC_FLAT_C - LABEL_DESC_GDT
Selector_Video equ LABEL_DESC_VIDEO - LABEL_DESC_GDT
Selector_Loader_Flat_RW equ 8
Selector_Loader_Flat_C equ 16
GDT_Len equ $ - LABEL_DESC_GDT
GDT_Ptr: dw GDT_Len - 1
dd 0
A: db 'A'
[section .bss]
Stack_Space resb 2 * 1024
Top_Of_Stack:
[section .text]
global _start
_start:
mov ax,Selector_Loader_Flat_RW
mov ds,ax
mov es,ax
mov eax,LABEL_DESC_GDT
mov dword [GDT_Ptr],eax
lgdt [GDT_Ptr]
mov ax,Selector_Flat_RW
mov ds,ax
mov es,ax
mov ss,ax
mov esp,Top_Of_Stack
jmp Selector_Flat_C:LABEL_TEST
LABEL_TEST:
mov ax,Selector_Video
mov gs,ax
mov ah,0ch
mov byte al,[A]
mov [gs:(80 * 20) * 2],ax
hlt
这里没有像作者那样把GDT从loader拷到kernel中,而是直接分配填充GDT,代码很简单,无需赘言,最后附图一张: