[033][x86汇编语言]第十四章|[033][x86汇编语言]第十四章 子程序load_relocate_program源码(增加注释)
学习笔记
【[033][x86汇编语言]第十四章|[033][x86汇编语言]第十四章 子程序load_relocate_program源码(增加注释)】《x86汇编语言:从实模式到保护模式》子程序load_relocate_program 结构
https://www.jianshu.com/p/d481cb547e9f
https://www.jianshu.com/p/adb70daa6d2c子程序load_relocate_program 完整源码
;
-------------------------------------------------------------------------------
load_relocate_program:;
加载并重定位用户程序
;
输入: PUSH 逻辑扇区号
;
PUSH 任务控制块基地址
;
输出:无
pushad;
全部双字通用寄存器push ds
push esmov ebp,esp;
为访问 通过堆栈传递的参数 做准备mov ecx,mem_0_4_gb_seg_sel
mov es,ecxmov esi,[ebp+11*4];
ebp默认使用段寄存器SS 取出TCB的基地址;
-------------------------------------------------------------------
;
1、初始化LDT
;
-------------------------------------------------------------------
mov ecx,160
call sys_routine_seg_sel:allocate_memory;
①分配内存,加载LDT
mov [es:esi+0x0c],ecx;
②登记LDT基地址到TCB
mov word [es:esi+0x0a],0xffff;
③登记LDT初始的界限值到TCB;
------------------------------------------------------------------
;
2、加载用户程序
;
------------------------------------------------------------------
;
以下开始加载用户程序
mov eax,core_data_seg_sel
mov ds,eax;
DS切换到内核程序数据段mov eax,[ebp+12*4];
取出用户程序起始逻辑扇区号
mov ebx,core_buf;
缓冲区用于存放用户程序头部段
call sys_routine_seg_sel:read_hard_disk_0;
以下判断整个用户程序有多大
mov eax,[core_buf];
程序尺寸
mov ebx,eax
and ebx,0xfffffe00;
使之512字节对齐
add ebx,512
test eax,0x000001ff
cmovnz eax,ebxmov ecx,eax
call sys_routine_seg_sel:allocate_memory;
①分配内存,加载用户程序
mov [es:esi+0x06],ecx;
②登记程序加载基地址到TCB中mov ebx,ecx
xor edx,edx
mov ecx,512
div ecx
mov ecx,eax;
总扇区数mov eax,mem_0_4_gb_seg_sel
mov ds,eaxmov eax,[ebp+12*4];
起始扇区号
.b1:
call sys_routine_seg_sel:read_hard_disk_0
inc eax
loop .b1;
循环读,知道读完整个用户程序;
----------------------------------------------------------------------
;
4、创建局部描述符表LDT
;
----------------------------------------------------------------------
mov edi,[es:esi+0x06];
获得程序加载基地址;
DS 已切换到0~4GB内存空间
;
ES 已切换到0~4GB内存空间
;
esi 指向TCB基地址
;
edi 指向用户程序加载基地址;
========================================================================
;
①
;
========================================================================
;
建立用户程序头部段描述符
mov eax,edi
mov ebx,[edi+0x04];
段长度
dec ebx;
段界限
mov ecx,0x0040f200;
字节粒度的数据段描述符,特权级 DPL=3
call sys_routine_seg_sel:make_seg_descriptor;
登记头部段描述符登记到LDT
mov ebx,esi;
TCB基地址
call fill_descriptor_in_ldt;
登记头部段选择子到TCB 以及 用户程序位于内存的头部段内
or cx,0000_0000_0000_0011B;
设置头部段选择子的RPL=3
mov [es:esi+0x44],cx;
登记头部段选择子到TCB
mov [edi+0x04],cx;
回写到用户程序位于内存的头部段内;
=========================================================================
;
②
;
=========================================================================
;
建立用户程序代码段描述符
mov eax,edi
add eax,[edi+0x14];
代码段起始线性地址
mov ebx,[edi+0x18];
段长度
dec ebx;
段界限
mov ecx,0x0040f800;
字节粒度的代码段描述符,特权级DPL=3
call sys_routine_seg_sel:make_seg_descriptor;
登记代码段描述符到LDT
mov ebx,esi;
TCB基地址
call fill_descriptor_in_ldt;
登记代码段选择子到用户程序头部
or cx,0000_0000_0000_0011B;
设置代码段选择子的特权级RPL=3
mov [edi+0x14],cx;
回写;
=========================================================================
;
③
;
=========================================================================
;
建立用户程序数据段描述符
mov eax,edi
add eax,[edi+0x1c];
数据段起始线性地址
mov ebx,[edi+0x20];
段长度
dec ebx;
段界限
mov ecx,0x0040f200;
字节粒度的数据段描述符,特权级DPL=3
call sys_routine_seg_sel:make_seg_descriptor;
登记数据段描述符到LDT
mov ebx,esi
call fill_descriptor_in_ldt;
登记数据段选择子到用户程序头部
or cx,0000_0000_0000_0011B;
设置数据段选择子特权级,RPL=3
mov [edi+0x1c],cx;
回写;
=========================================================================
;
④
;
=========================================================================
;
为用户程序堆栈段分配内存
mov ecx,[edi+0x0c]
mov ebx,0x000fffff;
4KB倍率
sub ebx,ecx;
得到段界限
mov eax,4096
mul ecx
mov ecx,eax
call sys_routine_seg_sel:allocate_memory;
=========================================================================
;
⑤
;
=========================================================================
;
建立用户程序堆栈段描述符
add eax,ecx;
得到堆栈的高端物理地址
mov ecx,0x00c0f600;
字节粒度的堆栈段描述符,特权级DPL=3
call sys_routine_seg_sel:make_seg_descriptor;
登记堆栈段描述符到LDT
mov ebx,esi
call fill_descriptor_in_ldt;
登记堆栈段选择子到用户程序头部
or cx,0000_0000_0000_0011B;
设置堆栈段选择子特权级RPL=3
mov [edi+0x08],cx;
回写;
--------------------------------------------------------------------------
;
5、重定位U-SALT表
;
--------------------------------------------------------------------------
mov eax,mem_0_4_gb_seg_sel
mov es,eaxmov eax,core_data_seg_sel
mov ds,eaxcldmov ecx,[es:edi+0x24];
U-SALT条目数
add edi,0x28.b2:
push ecx
push edimov ecx,salt_items
mov esi,salt
.b3:
push edi
push esi
push ecxmov ecx,64
repe cmpsd
jnz .b4
mov eax,[esi]
mov [es:edi-256],eax;
回写偏移地址
mov ax,[esi+4]
or ax,0000_0000_0000_0011B;
调用门选择子 特权级RPL=3
mov [es:edi-252],ax;
回填调用门选择子.b4:
pop ecx
pop esi
add esi,salt_item_len
pop edi
loop .b3pop edi
add edi,256
pop ecx
loop .b2;
-----------------------------------------------------------------------------
;
6、创建0、1、2特权级的栈
;
-----------------------------------------------------------------------------
mov esi,[ebp+11*4];
从堆栈中取得TCB线性地址;
==============================================================================
;
创建0特权级堆栈
;
==============================================================================
;
①登记0特权级堆栈尺寸到TCB
mov ecx,4096
mov eax,ecx
mov [es:esi+0x1a],ecx
shr dword [es:esi+0x1a],12
;
②分配内存,加载0特权级堆栈
call sys_routine_seg_sel:allocate_memory
;
③计算高端地址作为0特权级堆栈段基地址
add eax,ecx
;
④登记0特权级堆栈段基地址到TCB
mov [es:esi+0x1e],eax
;
⑤登记0特权级堆栈段描述符到LDT
mov ebx,0xffffe;
段长度
mov ecx,0x00c09600;
4KB粒度 读写 特权级0
call sys_routine_seg_sel:make_seg_descriptor
mov ebx,esi
call fill_descriptor_in_ldt
;
⑥登记0特权级堆栈段选择子到TCB
or cx,0000_0000_0000_0000B;
设置选择子的特权级 RPL=0
mov [es:esi+0x22],cx;
登记0特权级堆栈段选择子到TCB
;
⑦登记0特权级堆栈初始ESP到TCB
mov dword [es:esi+0x24],0;
==================================================================
;
创建1特权级堆栈
;
==================================================================
;
①登记1特权级堆栈尺寸到TCB
mov ecx,4096
mov eax,ecx
mov [es:esi+0x28],ecx
shr dword [es:esi+0x28],12
;
②分配内存,加载1特权级堆栈
call sys_routine_seg_sel:allocate_memory
;
③计算高端地址作为1特权级堆栈段基地址
add eax,ecx
;
④登记1特权级堆栈段基地址到TCB
mov [es:esi+0x2c],eax
;
⑤登记1特权级堆栈段描述符到LDT
mov ebx,0xffffe;
段长度
mov ecx,0x00c0b600;
4KB粒度 读写 特权级1
call sys_routine_seg_sel:make_seg_descriptor
mov ebx,esi
call fill_descriptor_in_ldt
;
⑥登记1特权级堆栈段选择子到TCB
or cx,0000_0000_0000_0001B;
设置选择子的特权级 RPL=1
mov [es:esi+0x30],cx;
登记1特权级堆栈段选择子到TCB
;
⑦登记1特权级堆栈初始ESP到TCB
mov dword [es:esi+0x32],0;
==================================================================
;
创建2特权级堆栈
;
==================================================================
;
①登记2特权级堆栈尺寸到TCB
mov ecx,4096
mov eax,ecx
mov [es:esi+0x36],ecx
shr dword [es:esi+0x36],12
;
②分配内存,加载1特权级堆栈
call sys_routine_seg_sel:allocate_memory
;
③计算高端地址作为2特权级堆栈段基地址
add eax,ecx
;
④登记2特权级堆栈段基地址到TCB
mov [es:esi+0x3a],eax
;
⑤登记2特权级堆栈段描述符到LDT
mov ebx,0xffffe;
段长度
mov ecx,0x00c0d600;
4KB粒度 读写 特权级2
call sys_routine_seg_sel:make_seg_descriptor
mov ebx,esi
call fill_descriptor_in_ldt
;
⑥登记2特权级堆栈段选择子到TCB
or cx,0000_0000_0000_0010B;
设置选择子的特权级 RPL=2
mov [es:esi+0x3e],cx;
登记1特权级堆栈段选择子到TCB
;
⑦登记2特权级堆栈初始ESP到TCB
mov dword [es:esi+0x40],0;
-----------------------------------------------------------------------
;
7、安装 LDT描述符 到GDT
;
-----------------------------------------------------------------------;
①创建LDT描述符
mov eax,[es:esi+0x0c];
LDT起始线性基地址
movzx ebx,word [es:esi+0x0a];
LDT当前界限值
mov ecx,0x00408200;
LDT描述符,特权级 DPL=0
call sys_routine_seg_sel:make_seg_descriptor
;
②安装 LDT描述符 到GDT
call sys_routine_seg_sel:set_up_gdt_descriptor
;
③将返回的 LDT选择子 登记到TCB
mov [es:esi+0x10],cx;
登记LDT选择子到TCB中;
-----------------------------------------------------------------------
;
8、创建任务状态段TSS
;
-----------------------------------------------------------------------;
①登记TSS界限值到TCB
mov ecx,104;
tss基本尺寸
mov [es:esi+0x12],cx
dec word [es:esi+0x12]
;
②分配内存,加载TSS
call sys_routine_seg_sel:allocate_memory
;
③登记TSS基地址到TCB
mov [es:esi+0x14],ecx;
-----------------------------------------------------------------------
;
9、登记基本的TSS表格内容
;
-----------------------------------------------------------------------
mov word [es:ecx+0],0;
没有前一个任务
;
①登记N特权级堆栈初始ESP、段选择子到TSS
mov edx,[es:esi+0x24]
mov [es:ecx+4],edx;
ESP0
mov edx,[es:esi+0x22]
mov [es:ecx+8],edx;
SS0mov edx,[es:esi+0x32]
mov [es:ecx+12],edx;
ESP1
mov edx,[es:esi+0x30]
mov [es:ecx+16],edx;
SS1mov edx,[es:esi+0x40]
mov [es:ecx+20],edx;
ESP2
mov edx,[es:esi+0x3e]
mov [es:ecx+24],edx;
SS2;
②登记当前任务的LDT选择子到TSS
mov dx,[es:esi+0x10]
mov [es:ecx+96],dx
;
③登记当前任务的I/O位图偏移到TSS
mov dx,[es:esi+0x12]
mov [es:ecx+102],dx
;
④设置TSS的T位值为零,表明这是唯一的任务
mov word [es:ecx+100],0;
-----------------------------------------------------------------------
;
10、安装TSS描述符到GDT
;
-----------------------------------------------------------------------
;
①创建TSS描述符
mov eax,[es:esi+0x14];
TSS起始线性地址
movzx ebx,word [es:esi+0x12];
TSS段长度
mov ecx,0x00408900;
TSS描述符 特权级DPL=0
call sys_routine_seg_sel:make_seg_descriptor
;
②安装TSS描述符到GDT
call sys_routine_seg_sel:set_up_gdt_descriptor
;
③将返回的TSS选择子登记到TCB
mov [es:esi+0x18],cx;
登记TSS选择子到TCB;
-----------------------------------------------------------------------
;
11、恢复压栈的寄存器、弹出参数、返回调用
;
-----------------------------------------------------------------------
pop es;
恢复到调用此过程前的es段
pop ds;
恢复到调用此过程前的ds段popadret 8;
丢弃调用本过程前压入的参数 ;
-------------------------------------------------------------------------------
推荐阅读
- 营养基础学20180331(课间随笔)??
- 【相信自己】20180330|【相信自己】20180330 D52 识字营践行第52 ?天
- 【140330】会有这样的时候
- #|阿尔法点亮LED灯(一)汇编语言
- “至简领导力之孝善断舍离033"之“帮忙不添乱”】(2092)
- x86架构应用如何向Arm架构低成本迁移
- 孩子王逗逗20190330(130)|孩子王逗逗20190330(130) - 草稿
- 20180331剽悍夜思——周复盘
- android x86虚拟机 网络正确配置
- 20190330分享