调用门

转载 2016年08月30日 22:55:52

门,顾名思义它是一扇门通向令一个地方,看一下门的结构里面有一个描述符和一个偏移值,门中定义了这扇门通向的目的地,当我们调用一个门的时候会到达这个地方:

门中的选择子:门中的偏移值,也即下图的selector:offset

这是我们代码中国定义的门的数据结构:

#define Gate(Selector,Offset,PCount,Attr)\
.2byte (Offset&0xffff);\
.2byte (Selector);\
.2byte (PCount&0x1f)|((Attr<<8)&0xff00);\
.2byte ((Offset>>16)&0xffff)

 

假设Selector_Gate_Call是调用门的描述符,执行lcall $Selector_Gate_Call,$0语句时偏移值($0)无意义,执行此语句后

CS=调用门中的选择子
IP=调用门中偏移值
CS:IP=全局描述符表中第(调用门中的选择子>>3)项描述符给出的段基址+调用门中偏移值


调用门的使用

定义调用门的描述符和选择子,如下面代码

/*门描述符*/
Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_PL0))

/*调用门选择子*/
.set Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START)

 

其中调用门中的选择子和描述符如下:

Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32)

.set  Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START)

 

Descriptor_CODE_GATE的初始化和代码段如下:

InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);

LABEL_CODE_G: 

    movl $((80*12+0)*2),%edi/*第10行,0列*/ 
    movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/ 
    movb $'G',%al/*要显示的字符*/ 
    movw %ax,%gs:(%edi)    
jmp .
 .set CodeGLen,(. - LABEL_CODE_G)

 

这时lcall $Selector_Gate_Call,$0就会看到红色的'G’打印出来,和ljmp Selector_Code_Gate,$0的效果是一样的,但是这并不是多此一举的,这涉及的特权级转换的问题,这里我们先不关心这些。

 

/*初始全局描述符Descriptor_CODE_GATE*/ 
InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);

具体代码如下:

  1. #define Descriptor(base,lim,attr)\  
  2. .word lim&0xffff;\  
  3. .word base&0xffff;\  
  4. .byte (base>>16)&0xff;\  
  5. .word ((lim>>8)&0xf00)|(attr&0x0f0ff);\  
  6. .byte ((base>>24)&0xff)    
  7.     
  8. /*    
  9. *InitDescrptor(Descriptor,SegBase)初始化描述符函数    
  10. *Descriptor:要初始化的描述符    
  11. *SegBase:段基址    
  12. */    
  13. #define InitDescrptor(Descriptor,SegBase)\  
  14. xor     %eax,%eax; \  
  15. mov     %cs,%ax  ; \  
  16. shl     $4,%eax  ; \  
  17. addl    $(SegBase), %eax ;\  
  18. movw    %ax, (Descriptor + 2);\  
  19. shr     $16, %eax;\  
  20. movb    %al, (Descriptor + 4);\  
  21. movb    %ah, (Descriptor + 7)    
  22.   
  23. #define Gate(Selector,Offset,PCount,Attr)\  
  24. .2byte (Offset&0xffff);\  
  25. .2byte (Selector);\  
  26. .2byte (PCount&0x1f)|((Attr<<8)&0xff00);\  
  27. .2byte ((Offset>>16)&0xffff)    
  28.   
  29. DA_386CGate = 0x8c  
  30. DA_PL0 = 0x00  
  31. DA_C   = 0x98    
  32. DA_32  = 0x4000    
  33. DA_DRW = 0x92    
  34. SA_TIL = 0x4    
  35. DA_LDT = 0x82    
  36.     
  37. .text    
  38. .globl start    
  39. .code16    
  40. start:    
  41.  jmpl $0x0, $code     
  42.      
  43. /**-----------------------------------------------------------------    
  44.  * 全局描述符表: GDT    
  45.  *-------------------------------*/         
  46. GDT_START:      
  47. Descriptor_DUMMY: Descriptor(0x0,0x0,0x0)    
  48. Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32)    
  49. Descriptor_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW)    
  50. Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32)  
  51.   
  52. /*门描述符*/   
  53. Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_PL0))    
  54. GDT_END:    
  55.     
  56. GdtPtr:    
  57.     .word (GDT_END-GDT_START)-1 # so does gdt     
  58.     .long GDT_START     # This will be rewrite by code.    
  59.   
  60. .set    selector_Code32,(Descriptor_CODE32-GDT_START)  
  61. .set    Selector_Video,(Descriptor_VIDEO-GDT_START)       
  62. .set  Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START)  
  63. /*调用门选择子*/  
  64. .set    Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START)  
  65.    
  66. msg:    
  67.  .string "Hello world!"    
  68.      
  69.      
  70. code:    
  71.     mov     %cs,%ax       
  72.     mov     %ax,%ds     
  73.     mov     %ax,%es        
  74.     mov     %ax,%ss      
  75.     mov  $0x8000,%sp      
  76.     /*显示HelloWorld字符串*/    
  77.     mov $msg   ,%ax    
  78.     mov %ax    ,%bp    
  79.     mov $12    ,%cx    
  80.     mov $0x1301,%ax    
  81.     mov $0x000c,%bx    
  82.     mov $0     ,%dl    
  83.         
  84.     int $0x10    
  85.         
  86.     
  87. /*初始全局描述符Descriptor_CODE32*/    
  88. InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32);    
  89.     
  90. /*初始全局描述符Descriptor_CODE_GATE*/    
  91. InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);    
  92.   
  93. /*加载gdtr即将全局描述符表gdt的首地址和gdt的界限赋给gdtr寄存器*/           
  94.     lgdt GdtPtr    
  95.     
  96. /*关中断*/    
  97.     cli    
  98.     
  99. /*打开地址线A20*/    
  100.     inb $0x92,%al    
  101.     or  $0x02,%al    
  102.     outb %al,$0x92    
  103.     
  104. /*设置cr0寄存器,切换到保护模式*/    
  105.     movl %cr0,%eax    
  106.     or   $1,%eax    
  107.     movl %eax,%cr0    
  108.     
  109.     
  110. /*真正进入保护模式,执行此命令后CS=0x8,IP=0*/    
  111.     ljmp $selector_Code32,$0    
  112.     
  113.   
  114. LABEL_SEG_CODE32:    
  115. .align  32    
  116. .code32    
  117.     
  118.     movw $Selector_Video,%ax    
  119.     movw %ax,%gs/* 视频段选择子(目的)*/    
  120.     movl $((80*11+79)*2),%edi/*第11行,79列*/    
  121.     movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/    
  122.     movb $'P',%al/*显示的字符*/    
  123.     movw %ax,%gs:(%edi)    
  124.          
  125.     #ljmp $Selector_Gate_Call,$0  
  126.     lcall $Selector_Gate_Call,$0    
  127.     
  128.         
  129. jmp .    
  130.         
  131. LABEL_CODE_G:    
  132.   
  133.     movl $((80*12+0)*2),%edi/*第10行,0列*/    
  134.     movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/    
  135.     movb $'G',%al/*要显示的字符*/    
  136.     movw %ax,%gs:(%edi)    
  137.       
  138. jmp .  
  139.    
  140. .set CodeGLen,(. - LABEL_CODE_G)    
  141.     
  142. .org 0x1fe, 0x90     
  143. .word 0xaa55   

执行结果如下图,可以看到红色的‘G’打印出来


在LABEL_CODE_G中我们打印完字符就让程序挺在了这里,这时候如下两段代码的效果是一样的。

ljmp $Selector_Gate_Call,$0
 lcall $Selector_Gate_Call,$0

但ljmp和lcall是不一样的,它们都会改变寄存器CS和IP实现程序的跳转,但lcall还会影响堆栈 ,段内跳转回将ip如栈段间跳转回将cs和ip入栈,等到lret执行时这个ip(或者cs和ip)会从堆栈中弹出。

下面我们就实现一个带返回的调用门:

  1. #define Descriptor(base,lim,attr)\  
  2. .word lim&0xffff;\  
  3. .word base&0xffff;\  
  4. .byte (base>>16)&0xff;\  
  5. .word ((lim>>8)&0xf00)|(attr&0x0f0ff);\  
  6. .byte ((base>>24)&0xff)    
  7.     
  8. /*    
  9. *InitDescrptor(Descriptor,SegBase)初始化描述符函数    
  10. *Descriptor:要初始化的描述符    
  11. *SegBase:段基址    
  12. */    
  13. #define InitDescrptor(Descriptor,SegBase)\  
  14. xor     %eax,%eax; \  
  15. mov     %cs,%ax  ; \  
  16. shl     $4,%eax  ; \  
  17. addl    $(SegBase), %eax ;\  
  18. movw    %ax, (Descriptor + 2);\  
  19. shr     $16, %eax;\  
  20. movb    %al, (Descriptor + 4);\  
  21. movb    %ah, (Descriptor + 7)    
  22.   
  23. #define Gate(Selector,Offset,PCount,Attr)\  
  24. .2byte (Offset&0xffff);\  
  25. .2byte (Selector);\  
  26. .2byte (PCount&0x1f)|((Attr<<8)&0xff00);\  
  27. .2byte ((Offset>>16)&0xffff)    
  28.   
  29. DA_386CGate = 0x8c  
  30. DA_PL0 = 0x00  
  31. DA_C   = 0x98    
  32. DA_32  = 0x4000    
  33. DA_DRW = 0x92    
  34. SA_TIL = 0x4    
  35. DA_LDT = 0x82    
  36.     
  37. .text    
  38. .globl start    
  39. .code16    
  40. start:    
  41.  jmpl $0x0, $code     
  42.      
  43. /**-----------------------------------------------------------------    
  44.  * 全局描述符表: GDT    
  45.  *-------------------------------*/         
  46. GDT_START:      
  47. Descriptor_DUMMY: Descriptor(0x0,0x0,0x0)    
  48. Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32)    
  49. Descriptor_VIDEO: Descriptor(0xb8000,0x0ffff,DA_DRW)    
  50. Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32)  
  51. Descriptor_LDT:   Descriptor(0x0,LDTLen - 1, DA_LDT)  
  52.   
  53. /*门描述符*/   
  54. Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_PL0))    
  55. GDT_END:    
  56.     
  57. GdtPtr:    
  58.     .word (GDT_END-GDT_START)-1 # so does gdt     
  59.     .long GDT_START     # This will be rewrite by code.    
  60.   
  61. /**-----------------------------------------------------------------    
  62.  * GDT中的选择子  
  63.  *-------------------------------*/   
  64. .set    selector_Code32,(Descriptor_CODE32-GDT_START)  
  65. .set    Selector_Video,(Descriptor_VIDEO-GDT_START)       
  66. .set  Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START)  
  67. .set    SelectorLDT,(Descriptor_LDT-GDT_START)  
  68. /*调用门选择子*/  
  69. .set    Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START)  
  70.   
  71. /**-----------------------------------------------------------------  
  72.  * 局部描述符表: LDT  
  73.  *-------------------------------*/  
  74. LDT_START:  
  75. /*                       段基址    段界限      属性*/  
  76. Descriptor_LDT_CODEA: Descriptor(0, CodeALen - 1, DA_C + DA_32)# Code, 32 位  
  77.   
  78. .set    LDTLen,(. - LDT_START)  
  79.   
  80. #LDT 选择子  
  81. .set  SelectorLDTCodeA,(0x0 + SA_TIL)  
  82.    
  83. msg:    
  84.  .string "Hello world!"    
  85.      
  86.      
  87. code:    
  88.     mov     %cs,%ax       
  89.     mov     %ax,%ds     
  90.     mov     %ax,%es        
  91.     mov     %ax,%ss      
  92.     mov  $0x8000,%sp      
  93.     /*显示HelloWorld字符串*/    
  94.     mov $msg   ,%ax    
  95.     mov %ax    ,%bp    
  96.     mov $12    ,%cx    
  97.     mov $0x1301,%ax    
  98.     mov $0x000c,%bx    
  99.     mov $0     ,%dl    
  100.         
  101.     int $0x10    
  102.         
  103.     
  104. /*初始全局描述符Descriptor_CODE32*/    
  105. InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32);   
  106.   
  107. /*初始全局描述符Descriptor_LDT*/  
  108. InitDescrptor(Descriptor_LDT,LDT_START);  
  109.     
  110. /*初始全局描述符Descriptor_CODE_GATE*/    
  111. InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);    
  112.   
  113. /*初始LDT 中的描述符Descriptor_LDT_CODEA*/  
  114. InitDescrptor(Descriptor_LDT_CODEA,LABEL_CODE_A);  
  115.   
  116. /*加载gdtr即将全局描述符表gdt的首地址和gdt的界限赋给gdtr寄存器*/           
  117.     lgdt GdtPtr    
  118.     
  119. /*关中断*/    
  120.     cli    
  121.     
  122. /*打开地址线A20*/    
  123.     inb $0x92,%al    
  124.     or  $0x02,%al    
  125.     outb %al,$0x92    
  126.     
  127. /*设置cr0寄存器,切换到保护模式*/    
  128.     movl %cr0,%eax    
  129.     or   $1,%eax    
  130.     movl %eax,%cr0    
  131.     
  132.     
  133. /*真正进入保护模式,执行此命令后CS=0x8,IP=0*/    
  134.     ljmp $selector_Code32,$0    
  135.     
  136.   
  137.   
  138. LABEL_SEG_CODE32:    
  139. .align  32    
  140. .code32    
  141.     
  142.     movw $Selector_Video,%ax    
  143.     movw %ax,%gs/* 视频段选择子(目的)*/    
  144.     movl $((80*11+79)*2),%edi/*第11行,79列*/    
  145.     movb $0x0c,%ah/*高四位表示黑底,低四位表示红字*/    
  146.     movb $'P',%al/*显示的字符*/    
  147.     movw %ax,%gs:(%edi)    
  148.          
  149.     lcall $Selector_Gate_Call,$0    
  150.     
  151.   
  152.     movw $SelectorLDT,%ax  
  153.         lldt %ax/*加载lgtr*/  
  154.   
  155.         ljmp    $SelectorLDTCodeA,$0    /* 跳入局部任务 LABEL_CODE_A*/  
  156.         
  157. jmp .    
  158.         
  159. LABEL_CODE_G:    
  160.   
  161.     movl $((80*12+0)*2),%edi/*第10行,0列*/    
  162.     movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/    
  163.     movb $'G',%al/*要显示的字符*/    
  164.     movw %ax,%gs:(%edi)    
  165.           
  166.         lret  
  167. .set CodeGLen,(. - LABEL_CODE_G)    
  168.   
  169. LABEL_CODE_A:  
  170.     movw $0x10,%ax  
  171.     movw %ax,%gs/* 视频段选择子(目的)*/  
  172.     movl $((80*12+10)*2),%edi/*第10行,0列*/  
  173.     movb $0x0c,%ah/*高四位0000表示黑底,低四位1100表示红字*/  
  174.     movb $'A',%al/*要显示的字符*/  
  175.     movw %ax,%gs:(%edi)  
  176.       
  177. loop3:  
  178.     jmp loop3  
  179. .set CodeALen,(. - LABEL_CODE_A)  
  180.     
  181. .org 0x1fe, 0x90     
  182. .word 0xaa55   


其结果是打印完'G'后返回,然后又打印出'A'如下图:

 

门也是一个描述符,我们放到了GDT中,我们通过门的选择子访问门,门通过它记录的选择子和偏移值又把我们传送到了目的地。

 

WINDOWS调用门驱动

  • 2009年11月16日 23:59
  • 30KB
  • 下载

特权级和调用门

转自:http://blog.csdn.net/wjwbin1986/article/details/6144058            http://1025250620.iteye.com/b...

一个操作系统的实现 不同特权级代码段之间的跳转 CPL DPL RPL 调用门

http://blog.csdn.net/begginghard/article/details/7262901 1、特权级 2、一致代码段和非一致代码段 3、DPL、RPL、CPL分别...

通过调用门进行控制转移 ——《x86汇编语言:从实模式到保护模式》读书笔记29

通过调用门进行控制转移 1.关于堆栈切换 2.通过调用门进行控制转移和返回的具体过程...

80386保护模式--GDT,LDT,TSS,调用门,特权级转移,附pmtest5代码详解

教材选择一个操作系统的实现,作者于渊,看此书前最好了有汇编语言,保护模式下的汇编(参考清华杨季文的80X86汇编语言程序设计教程),C语言,计算机组成原理,微机接口,操作系统相关知识。 一、8038...
  • jltxgcy
  • jltxgcy
  • 2013年03月10日 11:14
  • 3783

8-跨段提权与调用门

上一篇文章使用 jmp far 指令实现代码跨段,本质上就是改变 cs 段寄存器。但是我们发现,无论如何,jmp far 也无法更改 CPL。即使你的 RPL = 0,也是徒劳。有没有办法更改 cs ...

《Orange’s 一个操作系统的实现》3.保护模式7-特权级转移(通过调用门转移目标段-有特权级转换-理论)

A.关于堆栈    jmp指令:不影响堆栈    call指令:影响堆栈,对于短调用来说,call指令执行时会将下一条指令的eip压栈,到ret指令时,这个eip会被从堆栈中弹出。 ...

调用门详解

说明:此文是我将以前的两篇博文(读书笔记28和29)中的部分内容综合而来,如遇重复,请您自行跳过。...

通过retf和调用门实现特权级转换

不打算按别人的思路来,因为在我学的过程中上网查,发现网上的博客都是互相抄的,最终还是抄书的。Intel 64 和 IA-32架构处理器在进入保护模式之后,就会有一些列保护机制。其中出现了三个特别重要的...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:调用门
举报原因:
原因补充:

(最多只允许输入30个字)