[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 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                              ;丢弃调用本过程前压入的参数 
      
;-------------------------------------------------------------------------------
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342