[033][x86汇编语言]第十四章|[033][x86汇编语言]第十四章 子程序load_relocate_program源码(增加注释)

学习笔记

【[033][x86汇编语言]第十四章|[033][x86汇编语言]第十四章 子程序load_relocate_program源码(增加注释)】《x86汇编语言:从实模式到保护模式》
https://www.jianshu.com/p/d481cb547e9f
子程序load_relocate_program 结构
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; 丢弃调用本过程前压入的参数 ; -------------------------------------------------------------------------------

    推荐阅读