%include "inc.asm"
org 0x9000
jmp ENTRY_SEGMENT
[section .gdt]
; GDT definition
; 段基址, 段界限, 段属性
GDT_ENTRY : Descriptor 0, 0, 0
CODE32_DESC : Descriptor 0, Code32SegLen - 1, DA_C + DA_32
VIDEO_DESC : Descriptor 0xB8000, 0x07FFF, DA_DRWA + DA_32
STACK32_DESC : Descriptor 0, TopOfStack32, DA_DRW + DA_32
FUNCTION_DESC : Descriptor 0, FunctionSegLen - 1, DA_C + DA_32
; Gate Descriptor 调用门
; Call Gate 选择子, 偏移, 参数个数, 属性
FUNC_CG_ADD_DESC Gate FunctionSelector, CG_Add, 0, DA_386CGate
FUNC_CG_SUB_DESC Gate FunctionSelector, CG_Sub, 0, DA_386CGate
; GDT end
GdtLen equ $ - GDT_ENTRY
GdtPtr:
dw GdtLen - 1
dd 0
; GDT Selector
Code32Selector equ (0x0001 << 3) + SA_TIG + SA_RPL0
VideoSelector equ (0x0002 << 3) + SA_TIG + SA_RPL0
Stack32Selector equ (0x0003 << 3) + SA_TIG + SA_RPL0
FunctionSelector equ (0x0004 << 3) + SA_TIG + SA_RPL0
FuncCGAddSelector equ (0x0005 << 3) + SA_TIG + SA_RPL0
FuncCGSubSelector equ (0x0006 << 3) + SA_TIG + SA_RPL0
; end of [section .gdt]
TopOfStack16 equ 0x7c00
[section .s16]
[bits 16]
ENTRY_SEGMENT:
mov ax, cs
mov ds, ax
mov es, ax
mov ss, ax
mov sp, TopOfStack16
; initialize GDT for 32 bits code segment
mov esi, CODE32_SEGMENT
mov edi, CODE32_DESC
call InitDescItem
mov esi, STACK32_SEGMENT
mov edi, STACK32_DESC
call InitDescItem;初始化
mov esi, FUNCTION_SEGMENT
mov edi, FUNCTION_DESC
call InitDescItem
; initialize GDT pointer struct
mov eax, 0
mov ax, ds
shl eax, 4
add eax, GDT_ENTRY
mov dword [GdtPtr + 2], eax
; 1. load GDT
lgdt [GdtPtr]
; 2. close interrupt
cli
; 3. open A20
in al, 0x92
or al, 00000010b
out 0x92, al
; 4. enter protect mode
mov eax, cr0
or eax, 0x01
mov cr0, eax
; 5. jump to 32 bits code
jmp dword Code32Selector : 0;进入保护模式,跳转到CODE32_SEGMENT进入死循环
; esi --> code segment label
; edi --> descriptor label
InitDescItem:
push eax
mov eax, 0
mov ax, cs
shl eax, 4
add eax, esi
mov word [edi + 2], ax
shr eax, 16
mov byte [edi + 4], al
mov byte [edi + 7], ah
pop eax
ret
[section .s32]
[bits 32]
CODE32_SEGMENT:
mov ax, VideoSelector
mov gs, ax
mov ax, Stack32Selector
mov ss, ax
mov eax, TopOfStack32
mov esp, eax
mov ax, 2
mov bx, 1
call FuncCGAddSelector : 0
call FuncCGSubSelector : 0
jmp $
Code32SegLen equ $ - CODE32_SEGMENT
[section .func];代码段 32位
[bits 32]
FUNCTION_SEGMENT:
; ax --> a
; bx --> b
;
; return:
; cx --> a + b
AddFunc:
mov cx, ax;加法函数,寄存器相加
add cx, bx
retf;使用远调用
CG_Add equ AddFunc - $$;计算段内的偏移
; ax --> a
; bx --> b
;
; return:
; cx --> a - b
SubFunc:
mov cx, ax;减法函数,寄存器相减
sub cx, bx
retf
CG_Sub equ SubFunc - $$;计算段内的偏移
FunctionSegLen equ $ - FUNCTION_SEGMENT
[section .gs]
[bits 32]
STACK32_SEGMENT:
times 1024 * 4 db 0
Stack32SegLen equ $ - STACK32_SEGMENT
TopOfStack32 equ Stack32SegLen - 1
inc.sam 文件需要修改的是
; Segment Attribute
DA_32 equ 0x4000
DA_DR equ 0x90
DA_DRW equ 0x92
DA_DRWA equ 0x93
DA_C equ 0x98
DA_CR equ 0x9A
DA_CCO equ 0x9C
DA_CCOR equ 0x9E
; Segment Privilege
DA_DPL0 equ 0x00 ; DPL = 0
DA_DPL1 equ 0x20 ; DPL = 1
DA_DPL2 equ 0x40 ; DPL = 2
DA_DPL3 equ 0x60 ; DPL = 3
; Special Attribute
DA_LDT equ 0x82
DA_TaskGate equ 0x85 ; 任务门类型值
DA_386TSS equ 0x89 ; 可用 386 任务状态段类型值
DA_386CGate equ 0x8C ; 386 调用门类型值
DA_386IGate equ 0x8E ; 386 中断门类型值
DA_386TGate equ 0x8F ; 386 陷阱门类型值
; Selector Attribute
SA_RPL0 equ 0
SA_RPL1 equ 1
SA_RPL2 equ 2
SA_RPL3 equ 3
SA_TIG equ 0
SA_TIL equ 4
; 描述符
; 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 & 0xFFFF ; 段界限1
dw %1 & 0xFFFF ; 段基址1
db (%1 >> 16) & 0xFF ; 段基址2
dw ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
db (%1 >> 24) & 0xFF ; 段基址3
%endmacro ; 共 8 字节
; 门
; usage: Gate Selector, Offset, DCount, Attr
; Selector: dw
; Offset: dd
; DCount: db
; Attr: db
%macro Gate 4
dw (%2 & 0xFFFF) ; 偏移地址1
dw %1 ; 选择子
dw (%3 & 0x1F) | ((%4 << 8) & 0xFF00) ; 属性
dw ((%2 >> 16) & 0xFFFF) ; 偏移地址2
%endmacro
实验定义两个功能函数,并使其两个寄存器的值进行相加减,主要核心代码如下
AddFunc:
mov cx, ax;加法函数,寄存器相加
add cx, bx
retf;使用远调用
CG_Add equ AddFunc - $$;计算段内的偏移
; ax --> a
; bx --> b
;
; return:
; cx --> a - b
SubFunc:
mov cx, ax;减法函数,寄存器相减
sub cx, bx
retf
CG_Sub equ SubFunc - $$;计算段内的偏移
实验结果如图所示
实验过程
1.首先通过反编译找到关键的跳转命令,如图该命令的地址位0x90aa
2.接下来进入bochs下设置断点,并查看断点是否设置成功
3.接下来单步调试,发现代码成功跳转到[section .s32] [bits 32]中执行,通过代码可知当其跳转到call FuncCGAddSelector : 0该语句时,会跳转到定义的加减法功能中
4.在这里首先查看各个寄存器的值,发现在没有进行加法计算时,ax寄存器的值位2,bx寄存器的值为1,而此时的cx寄存器的值为15
5.在进入到定义的功能函数中,继续单步执行,当其执行完毕,跳转到[section .s32] [bits 32]中时,此时加法计算完毕,此时查看寄存器的值,如图所示,此时ax寄存器的值位2,bx寄存器的值为1,而此时的cx寄存器的值为3
说明call FuncCGAddSelector该函数是一个指针,指向Add函数
实验总结
1.门描述符是一种特殊的描述符,需要注册于段描述符表
2.调用门可以看作一个函数指针(保存具体函数的入口地址)
3.通过调用门选择子对相应的函数进行远调用
4.可以直接选择使用选择子:偏移地址的方式调用其它段的函数
5.使用调用门时偏移地址无意义
原文:https://blog.51cto.com/13475106/2489130