生活随笔
收集整理的這篇文章主要介紹了
调用门
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
門,顧名思義它是一扇門通向令一個地方,看一下門的結構里面有一個描述符和一個偏移值,門中定義了這扇門通向的目的地,當我們調用一個門的時候會到達這個地方:
門中的選擇子:門中的偏移值,也即下圖的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);
具體代碼如下:
[html] view plaincopy
#define?Descriptor(base,lim,attr)\??.word?lim&0xffff;\??.word?base&0xffff;\??.byte?(base>>16)&0xff;\??.word?((lim>>8)&0xf00)|(attr&0x0f0ff);\??.byte?((base>>24)&0xff)????????/*????*InitDescrptor(Descriptor,SegBase)初始化描述符函數????*Descriptor:要初始化的描述符????*SegBase:段基址????*/????#define?InitDescrptor(Descriptor,SegBase)\??xor?????%eax,%eax;?\??mov?????%cs,%ax??;?\??shl?????$4,%eax??;?\??addl????$(SegBase),?%eax?;\??movw????%ax,?(Descriptor?+?2);\??shr?????$16,?%eax;\??movb????%al,?(Descriptor?+?4);\??movb????%ah,?(Descriptor?+?7)??????#define?Gate(Selector,Offset,PCount,Attr)\??.2byte?(Offset&0xffff);\??.2byte?(Selector);\??.2byte?(PCount&0x1f)|((Attr<<8)&0xff00);\??.2byte?((Offset>>16)&0xffff)??????DA_386CGate?=?0x8c??DA_PL0?=?0x00??DA_C???=?0x98????DA_32??=?0x4000????DA_DRW?=?0x92????SA_TIL?=?0x4????DA_LDT?=?0x82????????.text????.globl?start????.code16????start:?????jmpl?$0x0,?$code??????????/**-----------------------------------------------------------------?????*?全局描述符表:?GDT?????*-------------------------------*/?????????GDT_START:??????Descriptor_DUMMY:?Descriptor(0x0,0x0,0x0)????Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32)????Descriptor_VIDEO:?Descriptor(0xb8000,0x0ffff,DA_DRW)????Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32)????/*門描述符*/???Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_PL0))????GDT_END:????????GdtPtr:????????.word?(GDT_END-GDT_START)-1?#?so?does?gdt?????????.long?GDT_START?????#?This?will?be?rewrite?by?code.??????.set????selector_Code32,(Descriptor_CODE32-GDT_START)??.set????Selector_Video,(Descriptor_VIDEO-GDT_START)???????.set??Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START)??/*調用門選擇子*/??.set????Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START)?????msg:?????.string?"Hello?world!"??????????????code:????????mov?????%cs,%ax???????????mov?????%ax,%ds?????????mov?????%ax,%es????????????mov?????%ax,%ss??????????mov??$0x8000,%sp??????????/*顯示HelloWorld字符串*/????????mov?$msg???,%ax????????mov?%ax????,%bp????????mov?$12????,%cx????????mov?$0x1301,%ax????????mov?$0x000c,%bx????????mov?$0?????,%dl????????????????int?$0x10????????????????/*初始全局描述符Descriptor_CODE32*/????InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32);????????/*初始全局描述符Descriptor_CODE_GATE*/????InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);??????/*加載gdtr即將全局描述符表gdt的首地址和gdt的界限賦給gdtr寄存器*/???????????????lgdt?GdtPtr????????/*關中斷*/????????cli????????/*打開地址線A20*/????????inb?$0x92,%al????????or??$0x02,%al????????outb?%al,$0x92????????/*設置cr0寄存器,切換到保護模式*/????????movl?%cr0,%eax????????or???$1,%eax????????movl?%eax,%cr0????????????/*真正進入保護模式,執行此命令后CS=0x8,IP=0*/????????ljmp?$selector_Code32,$0??????????LABEL_SEG_CODE32:????.align??32????.code32????????????movw?$Selector_Video,%ax????????movw?%ax,%gs/*?視頻段選擇子(目的)*/????????movl?$((80*11+79)*2),%edi/*第11行,79列*/????????movb?$0x0c,%ah/*高四位表示黑底,低四位表示紅字*/????????movb?$'P',%al/*顯示的字符*/????????movw?%ax,%gs:(%edi)?????????????????#ljmp?$Selector_Gate_Call,$0??????lcall?$Selector_Gate_Call,$0????????????????jmp?.????????????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)????????.org?0x1fe,?0x90?????.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)會從堆棧中彈出。
下面我們就實現一個帶返回的調用門:
[plain] view plaincopy
#define?Descriptor(base,lim,attr)\??.word?lim&0xffff;\??.word?base&0xffff;\??.byte?(base>>16)&0xff;\??.word?((lim>>8)&0xf00)|(attr&0x0f0ff);\??.byte?((base>>24)&0xff)????????/*????*InitDescrptor(Descriptor,SegBase)初始化描述符函數????*Descriptor:要初始化的描述符????*SegBase:段基址????*/????#define?InitDescrptor(Descriptor,SegBase)\??xor?????%eax,%eax;?\??mov?????%cs,%ax??;?\??shl?????$4,%eax??;?\??addl????$(SegBase),?%eax?;\??movw????%ax,?(Descriptor?+?2);\??shr?????$16,?%eax;\??movb????%al,?(Descriptor?+?4);\??movb????%ah,?(Descriptor?+?7)??????#define?Gate(Selector,Offset,PCount,Attr)\??.2byte?(Offset&0xffff);\??.2byte?(Selector);\??.2byte?(PCount&0x1f)|((Attr<<8)&0xff00);\??.2byte?((Offset>>16)&0xffff)??????DA_386CGate?=?0x8c??DA_PL0?=?0x00??DA_C???=?0x98????DA_32??=?0x4000????DA_DRW?=?0x92????SA_TIL?=?0x4????DA_LDT?=?0x82????????.text????.globl?start????.code16????start:?????jmpl?$0x0,?$code??????????/**-----------------------------------------------------------------?????*?全局描述符表:?GDT?????*-------------------------------*/?????????GDT_START:??????Descriptor_DUMMY:?Descriptor(0x0,0x0,0x0)????Descriptor_CODE32:Descriptor(0x0,0xffffffff,DA_C+DA_32)????Descriptor_VIDEO:?Descriptor(0xb8000,0x0ffff,DA_DRW)????Descriptor_CODE_GATE:Descriptor(0x0,CodeGLen,DA_C+DA_32)??Descriptor_LDT:???Descriptor(0x0,LDTLen?-?1,?DA_LDT)????/*門描述符*/???Descriptor_Gate_Call:Gate(Selector_Code_Gate,0,0,(DA_386CGate+DA_PL0))????GDT_END:????????GdtPtr:????????.word?(GDT_END-GDT_START)-1?#?so?does?gdt?????????.long?GDT_START?????#?This?will?be?rewrite?by?code.??????/**-----------------------------------------------------------------?????*?GDT中的選擇子???*-------------------------------*/???.set????selector_Code32,(Descriptor_CODE32-GDT_START)??.set????Selector_Video,(Descriptor_VIDEO-GDT_START)???????.set??Selector_Code_Gate,(Descriptor_CODE_GATE-GDT_START)??.set????SelectorLDT,(Descriptor_LDT-GDT_START)??/*調用門選擇子*/??.set????Selector_Gate_Call,(Descriptor_Gate_Call-GDT_START)????/**-----------------------------------------------------------------???*?局部描述符表:?LDT???*-------------------------------*/??LDT_START:??/*???????????????????????段基址????段界限??????屬性*/??Descriptor_LDT_CODEA:?Descriptor(0,?CodeALen?-?1,?DA_C?+?DA_32)#?Code,?32?位????.set????LDTLen,(.?-?LDT_START)????#LDT?選擇子??.set??SelectorLDTCodeA,(0x0?+?SA_TIL)?????msg:?????.string?"Hello?world!"??????????????code:????????mov?????%cs,%ax???????????mov?????%ax,%ds?????????mov?????%ax,%es????????????mov?????%ax,%ss??????????mov??$0x8000,%sp??????????/*顯示HelloWorld字符串*/????????mov?$msg???,%ax????????mov?%ax????,%bp????????mov?$12????,%cx????????mov?$0x1301,%ax????????mov?$0x000c,%bx????????mov?$0?????,%dl????????????????int?$0x10????????????????/*初始全局描述符Descriptor_CODE32*/????InitDescrptor(Descriptor_CODE32,LABEL_SEG_CODE32);?????/*初始全局描述符Descriptor_LDT*/??InitDescrptor(Descriptor_LDT,LDT_START);??????/*初始全局描述符Descriptor_CODE_GATE*/????InitDescrptor(Descriptor_CODE_GATE,LABEL_CODE_G);??????/*初始LDT?中的描述符Descriptor_LDT_CODEA*/??InitDescrptor(Descriptor_LDT_CODEA,LABEL_CODE_A);????/*加載gdtr即將全局描述符表gdt的首地址和gdt的界限賦給gdtr寄存器*/???????????????lgdt?GdtPtr????????/*關中斷*/????????cli????????/*打開地址線A20*/????????inb?$0x92,%al????????or??$0x02,%al????????outb?%al,$0x92????????/*設置cr0寄存器,切換到保護模式*/????????movl?%cr0,%eax????????or???$1,%eax????????movl?%eax,%cr0????????????/*真正進入保護模式,執行此命令后CS=0x8,IP=0*/????????ljmp?$selector_Code32,$0????????????LABEL_SEG_CODE32:????.align??32????.code32????????????movw?$Selector_Video,%ax????????movw?%ax,%gs/*?視頻段選擇子(目的)*/????????movl?$((80*11+79)*2),%edi/*第11行,79列*/????????movb?$0x0c,%ah/*高四位表示黑底,低四位表示紅字*/????????movb?$'P',%al/*顯示的字符*/????????movw?%ax,%gs:(%edi)?????????????????lcall?$Selector_Gate_Call,$0??????????????movw?$SelectorLDT,%ax??????????lldt?%ax/*加載lgtr*/????????????ljmp????$SelectorLDTCodeA,$0????/*?跳入局部任務?LABEL_CODE_A*/??????????jmp?.????????????LABEL_CODE_G:??????????movl?$((80*12+0)*2),%edi/*第10行,0列*/????????movb?$0x0c,%ah/*高四位0000表示黑底,低四位1100表示紅字*/????????movb?$'G',%al/*要顯示的字符*/????????movw?%ax,%gs:(%edi)??????????????????????lret??.set?CodeGLen,(.?-?LABEL_CODE_G)??????LABEL_CODE_A:??????movw?$0x10,%ax??????movw?%ax,%gs/*?視頻段選擇子(目的)*/??????movl?$((80*12+10)*2),%edi/*第10行,0列*/??????movb?$0x0c,%ah/*高四位0000表示黑底,低四位1100表示紅字*/??????movb?$'A',%al/*要顯示的字符*/??????movw?%ax,%gs:(%edi)????????loop3:??????jmp?loop3??.set?CodeALen,(.?-?LABEL_CODE_A)??????.org?0x1fe,?0x90?????.word?0xaa55???
其結果是打印完'G'后返回,然后又打印出'A'如下圖:
?
門也是一個描述符,我們放到了GDT中,我們通過門的選擇子訪問門,門通過它記錄的選擇子和偏移值又把我們傳送到了目的地。
?
總結
以上是生活随笔為你收集整理的调用门的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。