关闭

调用门

211人阅读 评论(0) 收藏 举报
分类:

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

门中的选择子:门中的偏移值,也即下图的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中,我们通过门的选择子访问门,门通过它记录的选择子和偏移值又把我们传送到了目的地。

 

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:710722次
    • 积分:12873
    • 等级:
    • 排名:第1121名
    • 原创:288篇
    • 转载:1964篇
    • 译文:3篇
    • 评论:11条
    最新评论