美文网首页
[033][x86汇编语言]第十四章 子程序load_reloc

[033][x86汇编语言]第十四章 子程序load_reloc

作者: AkuRinbu | 来源:发表于2018-06-10 17:42 被阅读28次

学习笔记

《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 es
        
        mov ebp,esp                 ;为访问 通过堆栈传递的参数 做准备
        
        mov ecx,mem_0_4_gb_seg_sel
        mov es,ecx
        
        mov 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,ebx
        
        mov 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,eax
        
            mov 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,eax
        
        mov eax,core_data_seg_sel
        mov ds,eax
        
        cld
        
        mov ecx,[es:edi+0x24]       ;U-SALT条目数
        add edi,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
            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 .b3
            
            
            pop 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              ;SS0
        
        mov edx,[es:esi+0x32]           
        mov [es:ecx+12],edx             ;ESP1
        mov edx,[es:esi+0x30]           
        mov [es:ecx+16],edx             ;SS1
        
        mov 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段
      
         popad
      
         ret 8                              ;丢弃调用本过程前压入的参数 
      
;-------------------------------------------------------------------------------

相关文章

网友评论

      本文标题:[033][x86汇编语言]第十四章 子程序load_reloc

      本文链接:https://www.haomeiwen.com/subject/pwqqeftx.html