在前面的建立GDT的代码中,只是用db,dw直接来写二进制的数据,当我们要在GDT中添加很多描述符的时候,这样做就显得很晦涩难懂。在这里我们就建立1个宏,此宏以比较方便的方法来建立1个描述符,有3个入口参数,分别是段基址,段界限和段属性,代码如下:
- ;%1 Base
- ;%2 Limit
- ;%3 Attr
- %macro Descriptor 3
- dw %2 & 0ffffh
- dw %1 & 0ffffh
- db (%1 >> 16) & 0ffh
- db %3 & 0ffh
- db ((%3 >> 8) & 0ffh) | ((%2 >> 16) & 0fh)
- db (%1 >> 24) & 0ffh
- %endmacro
我们看到,就是把入口参数通过移位和逻辑操作符来分隔到合适的地方,对照着描述符的结构就可以很轻松地完成此工作。
还有1个地方可以抽象,就是填充描述符的段基址的代码,如果要填充很多个描述符的段基址,那么重复的代码就会很多,可以选择用函数或者宏来实现,我们这里用宏来实现吧。入口地址有2个,一个是段描述符在实模式下的偏移,另一个是目标代码段的偏移,代码如下:
- ;%1 Descriptor's Offset
- ;%2 Segment's Offset
- %macro Fill_Descriptor 2
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,%2
- mov word [%1 + 2],ax
- shr eax,16
- mov byte [%1 + 4],al
- mov byte [%1 + 7],ah
- %endmacro
这样我们的代码就可以简洁很多了,下面在上一节的基础上修改的代码:
- ;%1 Base
- ;%2 Limit
- ;%3 Attr
- %macro Descriptor 3
- dw %2 & 0ffffh
- dw %1 & 0ffffh
- db (%1 >> 16) & 0ffh
- db %3 & 0ffh
- db ((%3 >> 8) & 0ffh) | ((%2 >> 16) & 0fh)
- db (%1 >> 24) & 0ffh
- %endmacro
- ;%1 Descriptor's Offset
- ;%2 Segment's Offset
- %macro Fill_Descriptor 2
- xor eax,eax
- mov ax,cs
- shl eax,4
- add eax,%2
- mov word [%1 + 2],ax
- shr eax,16
- mov byte [%1 + 4],al
- mov byte [%1 + 7],ah
- %endmacro
- org 0100h
- jmp LABEL_BEGIN
- [section .gdt]
- LABEL_DESC_DUMMY:
- Descriptor 0,0,0
- LABEL_DESC_CODE32:
- Descriptor 0,0ffffh,409ch
- LABEL_DESC_VIDEO:
- Descriptor 0b8000h,0ffffh,4092h
- GDT_Len equ $ - LABEL_DESC_DUMMY
- GDT_Ptr:
- dw GDT_Len - 1
- dd 0
- Selector_Code32 equ LABEL_DESC_CODE32 - LABEL_DESC_DUMMY
- Selector_Video equ LABEL_DESC_VIDEO - LABEL_DESC_DUMMY
- [section .s16]
- [bits 16]
- LABEL_BEGIN:
- mov ax,cs
- mov ds,ax
- mov es,ax
- Fill_Descriptor LABEL_DESC_CODE32,LABEL_CODE32
- xor eax,eax
- mov ax,ds
- shl eax,4
- add eax,LABEL_DESC_DUMMY
- mov dword [GDT_Ptr + 2],eax
- lgdt [GDT_Ptr]
- cli
- in al,92h
- or al,00000010b
- out 92h,al
- mov eax,cr0
- or al,1
- mov cr0,eax
- jmp Selector_Code32:0
- [section .s32]
- [bits 32]
- LABEL_CODE32:
- mov ax,Selector_Video
- mov gs,ax
- mov ah,0ch
- mov al,'x'
- mov [gs:80 * 10],ax
- jmp $
运行结果与上一节相同。