zoukankan      html  css  js  c++  java
  • 第十六课 保护模式中的特权级(中)

    问题:

      如何在不同特权级的代码段之间跳转执行?

    一种新的描述符:门描述符(Gate Descriptor)

      通过门描述符在不同的特权级的代码间进行跳转

      根据应用场景的不同,门描述符分为:

        调用门(Call Gate)

        中断门(Interrupt  Gate)

        陷阱门(Trap Gate)

        任务门(Task Gate)

    门描述符的一个功能就是可以在不同特权级的代码间进行跳转。

    门描述符的内存结构:

      每一个门描述符占用8字节内存

      不同类型门描述符的内存含义不同

    汇编小贴士:

      汇编语言中的跳转方式

        段内跳转(近跳转):call , jmp,call调用还可以返回回来,jmp是无条件跳转,无法返回来

          参数为相对地址,函数调用时只需要保存当前偏移地址

          近跳转就是段内的跳转,例如在段内定义了一个函数,就可以直接使用call来调用这个函数了,只保存当前偏移地址,例如,跳转到离当前10个字节的地址处执行,就只需将10保存下来,然后跳转执行,执行完之后将10拿出来,向回退10个字节就可以了。

        段间跳转(远跳转):call far, jmp  far

          参数为选择子和偏移地址

          函数调用时需要同时保存段基地址和偏移地址

              远跳转就是从当前段跳转到另一个段

          例如:段间远跳转的call far,将当前段的基地址即选择子保存下来,将当前段的偏移地址也保存下来。就是保存CS和IP的值。

    调用门实验:

    inc.asm

     1 ; Segment Attribute
     2 DA_32    equ    0x4000
     3 DA_DR    equ    0x90
     4 DA_DRW   equ    0x92
     5 DA_DRWA  equ    0x93
     6 DA_C     equ    0x98
     7 DA_CR    equ    0x9A
     8 DA_CCO   equ    0x9C
     9 DA_CCOR  equ    0x9E
    10 
    11 ; Segment Privilege
    12 DA_DPL0  equ   0x00        ; DPL = 0
    13 DA_DPL1  equ   0x20        ; DPL = 1
    14 DA_DPL2  equ   0x40        ; DPL = 2
    15 DA_DPL3  equ   0x60        ; DPL = 3
    16 
    17 ; Special Attribute
    18 DA_LDT             equ        0x82
    19 DA_TaskGate        equ        0x85    ; 
    20 DA_386TSS        equ        0x89    ;
    21 DA_386CGate        equ        0x8C    ;
    22 DA_386IGate        equ        0x8E    ;
    23 DA_386tgATE        equ        0x8F    ;
    24 
    25 ; Selector Attribute
    26 SA_RPL0    equ    0
    27 SA_RPL1    equ    1
    28 SA_RPL2    equ    2
    29 SA_RPL3    equ    3
    30 
    31 SA_TIG    equ    0
    32 SA_TIL    equ    4
    33 
    34 ; 描述符
    35 ; usage: Descriptor Base, Limit, Attr
    36 ;        Base:  dd
    37 ;        Limit: dd (low 20 bits available)
    38 ;        Attr:  dw (lower 4 bits of higher byte are always 0)
    39 %macro Descriptor 3                              ; 段基址, 段界限, 段属性
    40     dw    %2 & 0xFFFF                         ; 段界限1
    41     dw    %1 & 0xFFFF                         ; 段基址1
    42     db    (%1 >> 16) & 0xFF                   ; 段基址2
    43     dw    ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
    44     db    (%1 >> 24) & 0xFF                   ; 段基址3
    45 %endmacro                                     ; 共 8 字节
    46 
    47 ;Gate
    48 ; usage : Gate Selector, Offset, DCount, Attr
    49 ;         Selector : dw
    50 ;          Offset   : dd
    51 ;          DCount   : db
    52 ;          Attr       : db
    53 %macro Gate 4
    54     dw        (%2 & 0xFFFF)                        ; pianyidizhi1
    55     dw        %1                                    ; xuanzezi
    56     dw        (%3 & 0x1F) | ((%4 << 8) & 0xFF00)    ; shu xing
    57     dw        ((%2 >> 16) & 0xFFFF)                ; pianyidizhi2
    58 %endmacro

    17-23行和53-58行是我们新添加的门相关的定义。

    loader.asm如下:

      1 %include "inc.asm"
      2 
      3 org 0x9000
      4 
      5 jmp ENTRY_SEGMENT
      6 
      7 [section .gdt]
      8 ; GDT definition
      9 ;                                 段基址,       段界限,       段属性
     10 GDT_ENTRY       :     Descriptor    0,            0,           0
     11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
     12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
     13 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32 
     14 FUNCTION_DESC    :     Descriptor    0,      FunctionSegLen - 1, DA_C + DA_32
     15 ; Gate Descriptor 
     16 ; Call Gate                       xuanzezi            pianyi    canshugeshu      shuxing
     17 FUNC_CG_ADD_DESC  :   Gate        FunctionSelector,      CG_Add,         0,           DA_386CGate    
     18 FUNC_CG_SUB_DESC  :   Gate        FunctionSelector,      CG_Sub,         0,           DA_386CGate
     19 ; GDT end
     20 
     21 GdtLen    equ   $ - GDT_ENTRY
     22 
     23 GdtPtr:
     24           dw   GdtLen - 1
     25           dd   0
     26           
     27           
     28 ; GDT Selector
     29 
     30 Code32Selector        equ (0x0001 << 3) + SA_TIG + SA_RPL0
     31 VideoSelector         equ (0x0002 << 3) + SA_TIG + SA_RPL0
     32 Stack32Selector       equ (0x0003 << 3) + SA_TIG + SA_RPL0
     33 FunctionSelector      equ (0x0004 << 3) + SA_TIG + SA_RPL0
     34 FuncCGAddSelector      equ (0x0005 << 3) + SA_TIG + SA_RPL0
     35 FuncCGSubSelector      equ (0x0006 << 3) + SA_TIG + SA_RPL0
     36 
     37 ; end of [section .gdt]
     38 
     39 TopOfStack16    equ  0x7c00
     40 
     41 [section .s16]
     42 [bits 16]
     43 ENTRY_SEGMENT:
     44     mov ax, cs
     45     mov ds, ax
     46     mov es, ax
     47     mov ss, ax
     48     mov sp, TopOfStack16
     49     
     50     ; initialize GDT for 32 bits code segment
     51     mov esi, CODE32_SEGMENT
     52     mov edi, CODE32_DESC
     53     
     54     call InitDescItem
     55     
     56     mov esi, STACK32_SEGMENT
     57     mov edi, STACK32_DESC
     58     
     59     call InitDescItem
     60     
     61     mov esi, FUNCTION_SEGMENT
     62     mov edi, FUNCTION_DESC
     63     
     64     call InitDescItem
     65     
     66     ; initialize GDT pointer struct
     67     mov eax, 0
     68     mov ax, ds
     69     shl eax, 4
     70     add eax, GDT_ENTRY
     71     mov dword [GdtPtr + 2], eax
     72 
     73     ; 1. load GDT
     74     lgdt [GdtPtr]
     75     
     76     ; 2. close interrupt
     77     cli 
     78     
     79     ; 3. open A20
     80     in al, 0x92
     81     or al, 00000010b
     82     out 0x92, al
     83     
     84     ; 4. enter protect mode
     85     mov eax, cr0
     86     or eax, 0x01
     87     mov cr0, eax
     88     
     89     ; 5. jump to 32 bits code
     90     jmp dword Code32Selector : 0
     91 
     92     
     93 ; esi    --> code segment label
     94 ; edi    --> descriptor label
     95 InitDescItem:
     96     push eax
     97     
     98     mov eax, 0
     99     mov ax, cs
    100     shl eax, 4
    101     add eax, esi
    102     mov word [edi + 2], ax
    103     shr eax, 16
    104     mov byte [edi + 4], al
    105     mov byte [edi + 7], ah
    106     
    107     pop eax
    108     
    109     ret
    110      
    111 [section .s32]
    112 [bits 32]
    113 CODE32_SEGMENT:
    114     mov ax, VideoSelector
    115     mov gs, ax
    116     
    117     mov ax, Stack32Selector
    118     mov ss, ax
    119     
    120     mov eax, TopOfStack32
    121     mov esp, eax
    122     
    123     mov ax, 2
    124     mov bx, 1
    125     
    126     call FuncCGAddSelector : 0
    127     
    128     jmp $
    129 
    130 Code32SegLen    equ    $ - CODE32_SEGMENT
    131 
    132 [section .func]
    133 [bits 32]
    134 FUNCTION_SEGMENT:
    135 
    136 ; ax  -->  a
    137 ; bx  -->  b
    138 ; 
    139 ; return 
    140 ;      cx  --> a + b
    141 AddFunc:
    142     mov cx, ax
    143     add cx, bx
    144     retf
    145 
    146 CG_Add        equ        AddFunc - $$
    147 
    148 ; ax  -->  a
    149 ; bx  -->  b
    150 ; 
    151 ; return 
    152 ;      cx  --> a - b
    153 SubFunc:
    154     mov cx, ax
    155     sub cx, bx
    156     retf
    157     
    158 CG_Sub        equ        SubFunc - $$
    159 
    160 FunctionSegLen   equ  $ - FUNCTION_SEGMENT
    161 
    162 [section .gs]
    163 [bits 32]
    164 STACK32_SEGMENT:
    165     times 1024 * 4 db 0
    166     
    167 Stack32SegLen    equ $ - STACK32_SEGMENT
    168 TopOfStack32    equ Stack32SegLen - 1

    我们新定义了一个func段,在里面定义了AddFunc和SubFunc函数。第14行将func段的描述符加入了全局段描述符表。

    17、18行将两个门描述符加入了全局段描述符表。

    33-35行分别是这几个新添加的段描述符的选择子。

    下面我们单步执行:

    首先使用ndisasm -o 0x9000  loader > loader.txt将可执行程序进行反汇编,结果如下:

    我们重点关注跳转第58行的跳转这里。

    打断点执行:

    将ax,bx赋值准备跳转,这时的cx值如下:

    执行函数,cx的值有变化:

    因为只是加的最低位,所以高位的那个9我们不用关心。

    通过以下的调用方式我们可以得到同样的结果:

    126、127行直接使用段基址加段内偏移的方式调用。

    将使用调用门的方式截图如下:

    126、127现在是使用调用门的方式,冒号后面的0在这里没有什么意义,只是为了语法需要,如果去掉冒号和0,编译器会认为这是一个段内的函数调用。

    使用调用门选择子时,程序会根据选择子找到描述符,然后根据描述符中的选择子和偏移再去调用函数。这个调用门选择子在这里相当于一个函数指针。

    实验结论:

      门描述符是一种特殊的描述符,需要注册于段描述符表

      调用门可以看做一个函数指针(保存具体函数的入口地址)

      通过调用门选择子对相应的函数进行远调用(call far)

      可以直接使用  选择子:偏移地址  的方式调用其他段的函数

      使用调用门时偏移地址无意义,仅仅是语法需要

    历史遗留问题:

      保护模式下的不同段之间如何进行代码复用(如:调用同一个函数)?

    解决方案:

      将不同代码段中需要复用的函数定义到独立的段中(retf, f是far的意思)

      计算每一个可复用函数的偏移量(FuncName - $$)

      通过   段选择子:偏移地址   的方式对目标函数进行远调用

    对程序进行重构:

      1 %include "inc.asm"
      2 
      3 org 0x9000
      4 
      5 jmp ENTRY_SEGMENT
      6 
      7 [section .gdt]
      8 ; GDT definition
      9 ;                                 段基址,       段界限,       段属性
     10 GDT_ENTRY       :     Descriptor    0,            0,           0
     11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32
     12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32
     13 DATA32_DESC     :     Descriptor    0,    Data32SegLen  - 1,   DA_DR + DA_32
     14 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32    
     15 CODE16_DESC     :     Descriptor    0,           0xFFFF,       DA_C
     16 UPDATE_DESC     :     Descriptor    0,           0xFFFF,       DA_DRW
     17 TASK_A_LDT_DESC :     Descriptor    0,       TaskALdtLen - 1,  DA_LDT
     18 FUNCTION_DESC    :      Descriptor    0,         FunctionSegLen - 1, DA_C + DA_32
     19 ; GDT end
     20 
     21 GdtLen    equ   $ - GDT_ENTRY
     22 
     23 GdtPtr:
     24           dw   GdtLen - 1
     25           dd   0
     26           
     27           
     28 ; GDT Selector
     29 
     30 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
     31 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
     32 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
     33 Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
     34 Code16Selector    equ (0x0005 << 3) + SA_TIG + SA_RPL0
     35 UpdateSelector    equ (0x0006 << 3) + SA_TIG + SA_RPL0
     36 TaskALdtSelector  equ (0x0007 << 3) + SA_TIG + SA_RPL0
     37 FunctionSelector  equ (0x0008 << 3) + SA_TIG + SA_RPL0
     38 ; end of [section .gdt]
     39 
     40 TopOfStack16    equ  0x7c00
     41 
     42 [section .dat]
     43 [bits 32]
     44 DATA32_SEGMENT:
     45     DTOS                 db    "D.T.OS!", 0
     46     DTOS_OFFSET          equ   DTOS - $$
     47     HELLO_WORLD          db    "Hello World!", 0
     48     HELLO_WORLD_OFFSET   equ  HELLO_WORLD - $$
     49 
     50 Data32SegLen  equ $ - DATA32_SEGMENT
     51 
     52 [section .s16]
     53 [bits 16]
     54 ENTRY_SEGMENT:
     55     mov ax, cs
     56     mov ds, ax
     57     mov es, ax
     58     mov ss, ax
     59     mov sp, TopOfStack16
     60     
     61     mov [BACK_TO_REAL_MODE + 3], ax 
     62     
     63     ; initialize GDT for 32 bits code segment
     64     mov esi, CODE32_SEGMENT
     65     mov edi, CODE32_DESC
     66     
     67     call InitDescItem
     68     
     69     mov esi, DATA32_SEGMENT
     70     mov edi, DATA32_DESC
     71     
     72     call InitDescItem
     73     
     74     mov esi, DATA32_SEGMENT
     75     mov edi, STACK32_DESC
     76     
     77     call InitDescItem
     78     
     79     mov esi, CODE16_SEGMENT
     80     mov edi, CODE16_DESC
     81     
     82     call InitDescItem
     83     
     84     mov esi, TASK_A_LDT_ENTRY
     85     mov edi, TASK_A_LDT_DESC
     86     
     87     call InitDescItem
     88     
     89     mov esi, TASK_A_CODE32_SEGMENT
     90     mov edi, TASK_A_CODE32_DESC
     91     
     92     call InitDescItem
     93     
     94     mov esi, TASK_A_DATA32_SEGMENT
     95     mov edi, TASK_A_DATA32_DESC
     96     
     97     call InitDescItem
     98     
     99     mov esi, TASK_A_STACK32_SEGMENT
    100     mov edi, TASK_A_STACK32_DESC
    101     
    102     call InitDescItem
    103     
    104     mov esi, FUNCTION_SEGMENT
    105     mov edi, FUNCTION_DESC
    106     
    107     call InitDescItem
    108     
    109     ; initialize GDT pointer struct
    110     mov eax, 0
    111     mov ax, ds
    112     shl eax, 4
    113     add eax, GDT_ENTRY
    114     mov dword [GdtPtr + 2], eax
    115 
    116     ; 1. load GDT
    117     lgdt [GdtPtr]
    118     
    119     ; 2. close interrupt
    120     cli 
    121     
    122     ; 3. open A20
    123     in al, 0x92
    124     or al, 00000010b
    125     out 0x92, al
    126     
    127     ; 4. enter protect mode
    128     mov eax, cr0
    129     or eax, 0x01
    130     mov cr0, eax
    131     
    132     ; 5. jump to 32 bits code
    133     jmp dword Code32Selector : 0
    134 
    135 BACK_ENTRY_SEGMENT:
    136         mov ax, cs
    137         mov ds, ax
    138         mov es, ax
    139         mov ss, ax
    140         mov sp, TopOfStack16
    141         
    142         in al, 0x92
    143         and al, 11111101b
    144         out 0x92, al
    145         
    146         sti 
    147         
    148         mov bp, HELLO_WORLD
    149         mov cx, 12
    150         mov dx, 0
    151         mov ax, 0x1301
    152         mov bx, 0x0007
    153         int 0x10
    154         
    155         jmp $
    156 
    157 ; esi    --> code segment label
    158 ; edi    --> descriptor label
    159 InitDescItem:
    160     push eax
    161     
    162     mov eax, 0
    163     mov ax, cs
    164     shl eax, 4
    165     add eax, esi
    166     mov word [edi + 2], ax
    167     shr eax, 16
    168     mov byte [edi + 4], al
    169     mov byte [edi + 7], ah
    170     
    171     pop eax
    172     
    173     ret
    174     
    175 
    176 [section .16]
    177 [bits 16]
    178 CODE16_SEGMENT:
    179     mov ax, UpdateSelector
    180     mov ds, ax
    181     mov es, ax
    182     mov fs, ax
    183     mov gs, ax
    184     mov ss, ax
    185     
    186     mov eax, cr0
    187     and al, 11111110b
    188     mov cr0, eax
    189     
    190 BACK_TO_REAL_MODE:
    191     jmp 0 : BACK_ENTRY_SEGMENT
    192     
    193 Code16SegLen    equ $ - CODE16_SEGMENT
    194 
    195 [section .func]
    196 [bits 32]
    197 FUNCTION_SEGMENT:
    198 
    199 ; ds:ebp   --> string address
    200 ; bx       --> attribute
    201 ; dx       --> dh : row, dl : col
    202 PrintStringFunc:
    203     push ebp
    204     push eax
    205     push edi 
    206     push cx
    207     push dx
    208     
    209 print:
    210     mov cl, [ds:ebp]
    211     cmp cl, 0
    212     je end
    213     mov eax, 80
    214     mul dh
    215     add al, dl
    216     shl eax, 1
    217     mov edi, eax
    218     mov ah, bl
    219     mov al, cl
    220     mov [gs:edi], ax
    221     inc ebp
    222     inc dl
    223     jmp print
    224     
    225 end:
    226     pop dx
    227     pop cx
    228     pop edi
    229     pop eax
    230     pop ebp
    231     
    232     retf
    233     
    234 PrintString        equ        PrintStringFunc - $$
    235 
    236 FunctionSegLen        equ        $ - FUNCTION_SEGMENT
    237     
    238 [section .s32]
    239 [bits 32]
    240 CODE32_SEGMENT:
    241     mov ax, VideoSelector
    242     mov gs, ax
    243     
    244     mov ax, Stack32Selector
    245     mov ss, ax
    246     
    247     mov eax, TopOfStack32
    248     mov esp, eax
    249     
    250     mov ax, Data32Selector
    251     mov ds, ax
    252     
    253     mov ebp, DTOS_OFFSET
    254     mov bx, 0x0C
    255     mov dh, 12
    256     mov dl, 33
    257     
    258     call FunctionSelector : PrintString
    259     
    260     mov ebp, HELLO_WORLD_OFFSET
    261     mov bx, 0x0C
    262     mov dh, 13
    263     mov dl, 30
    264     
    265     call FunctionSelector : PrintString
    266     
    267     mov ax, TaskALdtSelector
    268     
    269     lldt ax
    270     
    271     jmp TaskACode32Selector : 0
    272     
    273     ;jmp Code16Selector : 0
    274 
    275     
    276 Code32SegLen    equ    $ - CODE32_SEGMENT
    277 
    278 [section .gs]
    279 [bits 32]
    280 STACK32_SEGMENT:
    281     times 1014 * 4 db 0
    282     
    283 Stack32SegLen    equ $ - STACK32_SEGMENT
    284 TopOfStack32    equ Stack32SegLen - 1
    285 
    286 
    287 ; ==================================
    288 ;        
    289 ;        Task A Code Segment
    290 ;
    291 ;===================================
    292 
    293 [section .task-a-ldt]
    294 ; Task A LDT definition
    295 ;                                        段基址                     段界限                段属性
    296 TASK_A_LDT_ENTRY:
    297 TASK_A_CODE32_DESC    :   Descriptor       0,               TaskACode32SegLen - 1,  DA_C + DA_32
    298 TASK_A_DATA32_DESC    :   Descriptor       0,               TaskAData32SegLen - 1,  DA_DR + DA_32
    299 TASK_A_STACK32_DESC   :   Descriptor       0,               TaskAStack32SegLen - 1, DA_DRW + DA_32
    300 
    301 TaskALdtLen        equ   $ - TASK_A_LDT_ENTRY
    302 
    303 ; Task A LDT  Selector
    304 TaskACode32Selector        equ  (0x0000 << 3) + SA_TIL + SA_RPL0
    305 TaskAData32Selector     equ     (0x0001 << 3) + SA_TIL + SA_RPL0
    306 TaskAStack32Selector    equ  (0x0002 << 3) + SA_TIL + SA_RPL0
    307 
    308 [section .task-a-dat]
    309 [bits 32]
    310 TASK_A_DATA32_SEGMENT:
    311     TASK_A_STRING        db   "This is Task A", 0
    312     TASK_A_STRING_OFFSET    equ     TASK_A_STRING - $$
    313     
    314 TaskAData32SegLen    equ $ - TASK_A_DATA32_SEGMENT
    315 
    316 [section .task-a-gs]
    317 [bits 32]
    318 TASK_A_STACK32_SEGMENT:
    319     times 1024 db 0
    320     
    321 TaskAStack32SegLen    equ     $ - TASK_A_STACK32_SEGMENT
    322 TaskATopOfStack32    equ     TaskAStack32SegLen - 1
    323 
    324 [section .task-a-s32]
    325 [bits 32]
    326 TASK_A_CODE32_SEGMENT:
    327 
    328     mov ax, VideoSelector
    329     mov gs, ax
    330     
    331     mov ax, TaskAStack32Selector
    332     mov ss, ax
    333     
    334     mov eax, TaskATopOfStack32
    335     mov esp, eax
    336     
    337     mov ax, TaskAData32Selector
    338     mov ds, ax
    339     
    340     mov ebp, TASK_A_STRING_OFFSET
    341     mov bx, 0x0c
    342     mov dh, 14
    343     mov dl, 29
    344     
    345     call FunctionSelector : PrintString
    346     
    347     jmp Code16Selector : 0
    348         
    349 TaskACode32SegLen     equ  $ - TASK_A_CODE32_SEGMENT

    运行结果如下:

     

    小结:

      门描述符是一种特殊的描述符,需要注册于段描述符表

      门描述符分为:调用门、中断门、陷阱门、任务门

      调用门可以看做一个函数指针(保存具体函数的入口地址)

      调用门选择子对应的函数调用方式为远调用(call  far)

  • 相关阅读:
    UVA——A Spy in the Metro(线性dp)
    IDEA运行jsp文件变成源码详细解决方案
    CF1105C Ayoub and Lost Array(dp+矩阵快速幂优化)
    牛客练习赛75——A广义肥波
    void * 指针和const 指针
    详解getchar()函数与缓冲区
    深入了解scanf() getchar()和gets()等函数之间的区别
    字符串和指针注意
    指针
    数组和字符串的小结
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9615490.html
Copyright © 2011-2022 走看看