内核统一管理描述符表,当用户程序需要获取段描述符时,就需要内核实现用户编程接口(API)
本书设计的具体实现方法是,用户程序在头部段列出所需的API的名称并258字节对齐(符号地址检索表),内核也有一个符合地址检索表,加载用户程序时拿用户程序中的符号地址检索表项搜索内核给出的表,用表内地址修改头部信息,将对应的过程地址覆盖掉原来的API名称
;用户程序内的符号地址检索表
salt_items dd (header_end-salt)/256 ;#0x24
salt: ;#0x28
PrintString db '@PrintString'
times 256-($-PrintString) db 0
TerminateProgram db '@TerminateProgram'
times 256-($-TerminateProgram) db 0
ReadDiskData db '@ReadDiskData'
times 256-($-ReadDiskData) db 0
;内核程序内的符号地址检索表
salt:
salt_1 db '@PrintString'
times 256-($-salt_1) db 0
dd put_string
dw sys_routine_seg_sel
salt_2 db '@ReadDiskData'
times 256-($-salt_2) db 0
dd read_hard_disk_0
dw sys_routine_seg_sel
salt_3 db '@PrintDwordAsHexString'
times 256-($-salt_3) db 0
dd put_hex_dword
dw sys_routine_seg_sel
salt_4 db '@TerminateProgram'
times 256-($-salt_4) db 0
dd return_point
dw core_code_seg_sel
;常量
salt_item_len equ $-salt_4
salt_items equ ($-salt)/salt_item_len
指令前常加REP
做循环比较
比较方向
重定位符号地址:
load_relocate_program:
... ; 建立完段描述符
;重定位SALT
mov eax,[edi+0x04]
mov es,eax ; es -> 用户程序头部段
mov eax,core_data_seg_sel
mov ds,eax ; ds -> 内核数据段
cld ;清除标志位
mov ecx,[es:0x24] ;用户程序的SALT条目数
mov edi,0x28 ;用户程序内的SALT位于头部内0x28处
.b2: ;外循环
push ecx
push edi
mov ecx,salt_items
mov esi,salt
.b3: ;内循环
push edi
push esi
push ecx
mov ecx,64 ;检索表中,每条目的比较次数
repe cmpsd ;每次比较4字节
jnz .b4
mov eax,[esi] ;若匹配,esi恰好指向内核salt其后的地址数据
mov [es:edi-256],eax ;将用户salt的字符串改写成偏移地址
mov ax,[esi+4]
mov [es:edi-252],ax ;以及段选择子
.b4:
pop ecx
pop esi
add esi,salt_item_len ;下一个内核salt条目
pop edi ;回到本次用户程序salt条目开头,从头比较
loop .b3
pop edi
add edi,256 ;下一个用户程序salt条目
pop ecx
loop .b2
mov ax,[es:0x04] ;取出用户程序头部的选择子,用于返回
pop es ;恢复到调用此过程前的es段
pop ds ;恢复到调用此过程前的ds段
pop edi
pop esi
pop edx
pop ecx
pop ebx
ret
用户程序调用内核过程
SECTION code vstart=0
start:
mov eax,ds
mov fs,eax ;ds, fs -> 用户程序头部段
mov eax,[stack_seg]
mov ss,eax
mov esp,0
mov eax,[data_seg]
mov ds,eax
mov ebx,message_1
call far [fs:PrintString]
mov eax,100 ;逻辑扇区号100
mov ebx,buffer ;缓冲区偏移地址
call far [fs:ReadDiskData] ;段间调用,读提前写入硬盘的文本文件内容
mov ebx,message_2
call far [fs:PrintString]
mov ebx,buffer
call far [fs:PrintString]
jmp far [fs:TerminateProgram] ;将控制权返回到系统
code_end:
十六进制形式显示双字:
put_hex_dword: ;在当前光标处以十六进制形式显示
;一个双字并推进光标
;输入:EDX=要转换并显示的数字
;输出:无
pushad ;将所有双字寄存器压栈
push ds
mov ax,core_data_seg_sel ;切换到核心数据段
mov ds,ax
mov ebx,bin_hex ;指向核心数据段内的转换表:bin_hex db '0123456789ABCDEF'
mov ecx,8
.xlt:
rol edx,4
mov eax,edx
and eax,0x0000000f
xlat ;查表指令
push ecx
mov cl,al
call put_char
pop ecx
loop .xlt
pop ds
popad
retf