1、特權級
2、一致代碼段和非一致代碼段
3、DPL、RPL、CPL分別代表的含義,存儲在什么位置,以及它們之間的關系
4、不同特權級數據段之間的訪問規則
5、不同特權級代碼段之間的轉移
6、代碼段之間的轉移對堆棧的影響
7、結合pmtest5.asm來見證不同特權級代碼段之間的跳轉
一、特權級
在IA32的分段機制下,特權級總共有4個特權級別,從高到低分別是0、1、2、3。數字越小表示的特權級越大。特權級如下圖所示:
較為核心的代碼和數據,將被存放在特權級較高的層級中。處理器將用這樣的機制來避免低特權級的任務在不被允許的情況下訪問位于高特權級的段。
二、一致代碼段 和 非一致代碼段
系統要安全,必須保證內核與用戶程序分離開,內核要安全,必須不能被用戶來打擾。但是有的時候,用戶程序也是需要訪問內核中的部分數據,那怎么辦?
于是操作系統就將內核中的段分為共享的代碼段和非共享的代碼段兩部分。
其中一致代碼段就是操作系統拿出來被共享的代碼段,可以被低特權級的用戶直接訪問的代碼。
一致代碼段的限制作用:
(1)特權級高的代碼段不允許訪問特權級低的代碼段:即內核態不允許調用用戶態下的代碼。
(2)特權級低的代碼段可以訪問特權級高的代碼段,但是當前的特權級不發生變化。即:用戶態可以訪問內核態的代碼,但是用戶態仍然是用戶態。
非一致代碼段:為了避免低特權級的訪問而被操作系統保護起來的系統代碼,也就是非共享代碼。
非一致代碼段的限制作用:
(1)只允許同特權級間訪問
(2)絕對禁止不同級間訪問,即:用戶態不能訪問內核態,內核態也不訪問用戶態。
下圖為一致碼段與非一致碼段的訪問規則:
三、CPL、DPL、RPL分別代表的含義,存儲在什么位置,以及它們之間的關系
1、CPL(Current Privilege Level)是當前執行的程序或任務的特權級。它被存儲在CS和SS的第0位和第1位上。通常情況下,CPL等于代碼的段的特權級。在遇到一致代碼段時,一致代碼段可以被相同或者更低特權級的代碼訪問。當處理器訪問一個與CPL特權級不同的一致代碼段時,CPL不會被改變。
2、DPL(Descriptor Privilege Level):DPL表示段或者門的特權級,它被存儲在段描述符或者門描述符的DPL字段中。當當前代碼段試圖訪問一個段或者門時,DPL將會和CPL以及段或門選擇子的RPL相比較,根據段或者門類型的不同,DPL將會被區別對待,下面介紹一下各種類型的段或者門的情況。
(1)數據段:DPL規定了可以訪問此段的最低特權級。比如,一個數據段的DPL是1,那么只有運行在CPL為0或者1的程序才有權訪問它。
(2)非一致代碼段(不使用調用門的情況下):DPL規定訪問此段的特權級。比如一個非一致代碼段的特權級為0,那么只有CPL為0的程序才可以訪問它。
(3)調用門:DPL規定了當前執行的程序或任務可以訪問此調用門的最低特權級(這與數據段的規則是一致的)。
(4)一致代碼段和通過調用門訪問的非一致代碼段:DPL規定了訪問此段的最高特權級。比如,一個一致代碼段的DPL是2,那么CPL為0和1的程序將無法訪問此段。
3、RPL(Requested Privilege Level):RPL是通過選擇子的第0位和第1位表現出來的。處理器通過檢查RPL和CPL來確認一個訪問請求是否合法。
四、不同特權級數據段之間的訪問規則
數據段中DPL規定了可以訪問此段的最低特權級,因此,對數據的訪問,只要CPL和RPL都小于被訪問的數據段的DPL就可以了,即CPL<=DPL和RPL<=DPL。
五、不同特權級代碼段之間的轉移
使用jmp或call指令可以實現下列4種轉移
(1)目標操作數包含目標代碼段的段選擇子。
(2)目標操作數指向一個包含目標代碼段選擇子的調用門描述符。
(3)目標操作數指向一個包含目標代碼段選擇子的TSS。
(4)目標操作數指向一個任務門,這個任務門指向一個包含目標代碼段選擇子的TSS。
這4種方式可以看做是兩大類,一類是通過jmp和call的直接轉移(上述第一種),另一類是通過某個描述?
符的間接轉移(上述第2,3,4種)。
1、通過jmp或call進行直接轉移
2、通過調用門進行轉移
(1)門描述符的結構
調用門描述符里面保存著目標代碼段的段選擇子,偏移量,以及屬性。
(2)調用門的使用方式
假設我們想由代碼A轉移到代碼B,運用一個調用門G,即調用門G中的目標選擇子指向代碼B的段。實際上,這個問題主要涉及這幾個元素:CPL、RPL、代碼B的DPL(記做DPL_B),調用門G的DPL(記做DPL_G)。
調用門使用時特權級檢驗的規則如下:
也就是說,通過調用門和call指令,可以實現從低特權級到高特權級的轉移,無論目標代碼段時一致的還是非一致的。
通過調用門和jmp指令,如果目標代碼段是一致的,則可以實現從低特權級到高特權級的轉移。如果目標代碼段是非一致的,則只能實現相同特權級的轉移。
六、代碼段之間的轉移對堆棧的影響
1、“長”跳轉/調用 和 “短”跳轉/調用
如果一個調用或跳轉指令時段間而不是段內進行的,那么我們稱之為“長”的(Far jmp/call),反之,如果在段內則是“短”的(Near jmp/call)。
那么長的和短的jmp或call有什么分別呢?
對于jmp而言,僅僅是結果不同罷了,短跳轉對應段內,長跳轉對應段間。
對于call來說,就比較復雜一些,因為call指令是會影響堆棧的,長調用和短調用對堆棧的影響是不同的。
下面我們討論短調用對堆棧的影響,call指令執行時下一條指令的eip壓棧,到ret指令執行時,這個eip會被從堆棧中彈出,
如下圖所示:
這是短調用的情況。
下面我們討論長調用對堆棧的影響,call指令執行時會將調用者的cs和eip壓棧,到ret指令執行時,這個eip和cs會被從堆棧中彈出,如下圖所示:
2、有特權級變換的轉移對堆棧的影響
在不同特權級下的堆棧段不同,所以每一個任務最多可能在4個特權級間轉移,所以,每個任務實際上需要4個堆棧。可是我們只有一個ss和一個esp,那么當發生堆棧切換,我們該從哪里獲得其余堆棧的ss和esp呢?
解決這個問題,需要一個數據結構TSS(Task-State Stack),如圖:
當堆棧發生切換時,內層的ss和esp就是從這里取得的,比如,我們當前所在的是ring3,當轉移至ring1時,堆棧將被自動切換到由ss1和esp1指定的位置。由于只是在由外層轉移到內層(低特權級到高特權級)切換時新堆棧才會從TSS中取得,所以TSS中沒有位于最外層的ring3的堆棧信息。
下面讓我們來看看整個的轉移過程是怎么樣的?
執行call前后堆棧段的變化:
(1)根據目標代碼段的DPL(新的CPL)從TSS中選擇應該切換至哪個ss和esp
(2)從TSS中讀取新的ss和esp。在這過程中如果發現ss、esp或者TSS界限錯誤都會導致無效TSS異常
(3)對ss描述符進行檢驗,如果發生錯誤,同樣產生#TS異常
(4)暫時性地保存當前ss和esp的值
(5)加載新的ss和esp
(6)將剛剛保存起來的ss和esp的值壓入新棧
(7)從調用者堆棧中將參數復制到被調用者堆棧(新堆棧)中,復制參數的數目由調用門中Param Count一項來決定。
(8)如果Param Count是零的話,將不會復制參數。
(9)將當前的cs和eip壓棧
(10)加載調用門中指定的新的cs和eip,開始執行被調用者過程。
執行ret前后堆棧段的變化:
(1)檢查保存的cs中的RPL以判斷返回時是否要變換特權級
(2)加載被調用者堆棧上的cs和eip(此時會進行代碼段描述符和選擇子類型和特權級檢驗)
(3)如果ret指令含有參數,則增加esp的值以跳過參數,然后esp將指向被保存過的調用者ss和esp。注意,ret的參數必須對應調用門中的Param Count的值
(4)加載ss和esp,切換到調用者堆棧,被調用者的ss和esp被丟棄。在這里將會進行ss描述符、esp、以及ss段描述符的檢驗
(5)如果ret指令含有參數,增加esp的值以跳過參數(此時已經在調用者堆棧中)
(6)檢查ds、es、fs、gs的值,如果其中哪一個寄存器指向的段的DPL小于CPL(此規則不適合于一致代碼段),那么一個空描述符會被加載到該寄存器中。
綜上所述,使用調用門的過程實際上分為兩部分,一部分是從低特權級到高特權級,通過調用門和call指令來實現;另一部分則是從高特權級到低特權級,通過ret指令來實現。
七、結合pmtest5.asm來見證不同特權級代碼段之間的跳轉
[html] view plaincopy
;?==========================================??;?pmtest5.asm??;?編譯方法:nasm?pmtest5.asm?-o?pmtest5.com??;?==========================================????%include????"pm.inc"????;?常量,?宏,?以及一些說明????org?0100h??????jmp?LABEL_BEGIN????[SECTION?.gdt]??;?GDT??;?????????????????????????????????????????段基址,?????????段界限?????,?屬性??LABEL_GDT:??????Descriptor?????????0,???????????????????0,?0????????????;?空描述符??LABEL_DESC_NORMAL:??Descriptor?????????0,??????????????0ffffh,?DA_DRW???????????;?Normal?描述符??LABEL_DESC_CODE32:??Descriptor?????????0,????SegCode32Len?-?1,?DA_C?+?DA_32?????;?非一致代碼段,?32??LABEL_DESC_CODE16:??Descriptor?????????0,??????????????0ffffh,?DA_C?????????;?非一致代碼段,?16??LABEL_DESC_CODE_DEST:???Descriptor?????????0,??SegCodeDestLen?-?1,?DA_C?+?DA_32?????;?非一致代碼段,?32??LABEL_DESC_CODE_RING3:??Descriptor?????????0,?SegCodeRing3Len?-?1,?DA_C?+?DA_32?+?DA_DPL3???;?非一致代碼段,?32??LABEL_DESC_DATA:????Descriptor?????????0,?????DataLen?-?1,?DA_DRW???????????;?Data??LABEL_DESC_STACK:???Descriptor?????????0,??????????TopOfStack,?DA_DRWA?+?DA_32??????;?Stack,?32?位??LABEL_DESC_STACK3:??Descriptor?????????0,?????????TopOfStack3,?DA_DRWA?+?DA_32?+?DA_DPL3;?Stack,?32?位??LABEL_DESC_TSS:?????Descriptor?????????0,??????????TSSLen?-?1,?DA_386TSS????????;?TSS??LABEL_DESC_VIDEO:???Descriptor???0B8000h,??????????????0ffffh,?DA_DRW?+?DA_DPL3?????;?顯存首地址????;?門????????????????????????????????????????????目標選擇子,???????偏移,?DCount,?屬性??LABEL_CALL_GATE_TEST:???Gate??????????SelectorCodeDest,??????????0,??????0,?DA_386CGate?+?DA_DPL3??;?GDT?結束????GdtLen??????equ?$?-?LABEL_GDT???;?GDT長度??GdtPtr??????dw??GdtLen?-?1??;?GDT界限??????????dd??0???????;?GDT基地址????;?GDT?選擇子??SelectorNormal??????equ?LABEL_DESC_NORMAL???-?LABEL_GDT??SelectorCode32??????equ?LABEL_DESC_CODE32???-?LABEL_GDT??SelectorCode16??????equ?LABEL_DESC_CODE16???-?LABEL_GDT??SelectorCodeDest????equ?LABEL_DESC_CODE_DEST????-?LABEL_GDT??SelectorCodeRing3???equ?LABEL_DESC_CODE_RING3???-?LABEL_GDT?+?SA_RPL3??SelectorData????????equ?LABEL_DESC_DATA?????-?LABEL_GDT??SelectorStack???????equ?LABEL_DESC_STACK????-?LABEL_GDT??SelectorStack3??????equ?LABEL_DESC_STACK3???-?LABEL_GDT?+?SA_RPL3??SelectorTSS?????equ?LABEL_DESC_TSS??????-?LABEL_GDT??SelectorVideo???????equ?LABEL_DESC_VIDEO????-?LABEL_GDT????SelectorCallGateTest????equ?LABEL_CALL_GATE_TEST????-?LABEL_GDT?+?SA_RPL3??;?END?of?[SECTION?.gdt]????[SECTION?.data1]?????;?數據段??ALIGN???32??[BITS???32]??LABEL_DATA:??SPValueInRealMode???dw??0??;?字符串??PMMessage:??????db??"In?Protect?Mode?now.?^-^",?0???;?進入保護模式后顯示此字符串??OffsetPMMessage?????equ?PMMessage?-?$??StrTest:????????db??"ABCDEFGHIJKLMNOPQRSTUVWXYZ",?0??OffsetStrTest???????equ?StrTest?-?$??DataLen?????????equ?$?-?LABEL_DATA??;?END?of?[SECTION?.data1]??????;?全局堆棧段??[SECTION?.gs]??ALIGN???32??[BITS???32]??LABEL_STACK:??????times?512?db?0??TopOfStack??equ?$?-?LABEL_STACK?-?1??;?END?of?[SECTION?.gs]??????;?堆棧段ring3??[SECTION?.s3]??ALIGN???32??[BITS???32]??LABEL_STACK3:??????times?512?db?0??TopOfStack3?equ?$?-?LABEL_STACK3?-?1??;?END?of?[SECTION?.s3]??????;?TSS?---------------------------------------------------------------------------------------------??[SECTION?.tss]??ALIGN???32??[BITS???32]??LABEL_TSS:??????????DD??0???????????;?Back??????????DD??TopOfStack??????;?0?級堆棧??????????DD??SelectorStack???????;???????????DD??0???????????;?1?級堆棧??????????DD??0???????????;???????????DD??0???????????;?2?級堆棧??????????DD??0???????????;???????????DD??0???????????;?CR3??????????DD??0???????????;?EIP??????????DD??0???????????;?EFLAGS??????????DD??0???????????;?EAX??????????DD??0???????????;?ECX??????????DD??0???????????;?EDX??????????DD??0???????????;?EBX??????????DD??0???????????;?ESP??????????DD??0???????????;?EBP??????????DD??0???????????;?ESI??????????DD??0???????????;?EDI??????????DD??0???????????;?ES??????????DD??0???????????;?CS??????????DD??0???????????;?SS??????????DD??0???????????;?DS??????????DD??0???????????;?FS??????????DD??0???????????;?GS??????????DD??0???????????;?LDT??????????DW??0???????????;?調試陷阱標志??????????DW??$?-?LABEL_TSS?+?2???;?I/O位圖基址??????????DB??0ffh????????????;?I/O位圖結束標志??TSSLen??????equ?$?-?LABEL_TSS??;?TSS?^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^??????[SECTION?.s16]??[BITS???16]??LABEL_BEGIN:??????mov?ax,?cs??????mov?ds,?ax??????mov?es,?ax??????mov?ss,?ax??????mov?sp,?0100h????????mov?[LABEL_GO_BACK_TO_REAL+3],?ax??????mov?[SPValueInRealMode],?sp????????;?初始化?16?位代碼段描述符??????mov?ax,?cs??????movzx???eax,?ax??????shl?eax,?4??????add?eax,?LABEL_SEG_CODE16??????mov?word?[LABEL_DESC_CODE16?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_CODE16?+?4],?al??????mov?byte?[LABEL_DESC_CODE16?+?7],?ah????????;?初始化?32?位代碼段描述符??????xor?eax,?eax??????mov?ax,?cs??????shl?eax,?4??????add?eax,?LABEL_SEG_CODE32??????mov?word?[LABEL_DESC_CODE32?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_CODE32?+?4],?al??????mov?byte?[LABEL_DESC_CODE32?+?7],?ah????????;?初始化測試調用門的代碼段描述符??????xor?eax,?eax??????mov?ax,?cs??????shl?eax,?4??????add?eax,?LABEL_SEG_CODE_DEST??????mov?word?[LABEL_DESC_CODE_DEST?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_CODE_DEST?+?4],?al??????mov?byte?[LABEL_DESC_CODE_DEST?+?7],?ah????????;?初始化數據段描述符??????xor?eax,?eax??????mov?ax,?ds??????shl?eax,?4??????add?eax,?LABEL_DATA??????mov?word?[LABEL_DESC_DATA?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_DATA?+?4],?al??????mov?byte?[LABEL_DESC_DATA?+?7],?ah????????;?初始化堆棧段描述符??????xor?eax,?eax??????mov?ax,?ds??????shl?eax,?4??????add?eax,?LABEL_STACK??????mov?word?[LABEL_DESC_STACK?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_STACK?+?4],?al??????mov?byte?[LABEL_DESC_STACK?+?7],?ah????????;?初始化堆棧段描述符(ring3)??????xor?eax,?eax??????mov?ax,?ds??????shl?eax,?4??????add?eax,?LABEL_STACK3??????mov?word?[LABEL_DESC_STACK3?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_STACK3?+?4],?al??????mov?byte?[LABEL_DESC_STACK3?+?7],?ah????????;?初始化Ring3描述符??????xor?eax,?eax??????mov?ax,?ds??????shl?eax,?4??????add?eax,?LABEL_CODE_RING3??????mov?word?[LABEL_DESC_CODE_RING3?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_CODE_RING3?+?4],?al??????mov?byte?[LABEL_DESC_CODE_RING3?+?7],?ah????????;?初始化?TSS?描述符??????xor?eax,?eax??????mov?ax,?ds??????shl?eax,?4??????add?eax,?LABEL_TSS??????mov?word?[LABEL_DESC_TSS?+?2],?ax??????shr?eax,?16??????mov?byte?[LABEL_DESC_TSS?+?4],?al??????mov?byte?[LABEL_DESC_TSS?+?7],?ah????????;?為加載?GDTR?作準備??????xor?eax,?eax??????mov?ax,?ds??????shl?eax,?4??????add?eax,?LABEL_GDT??????;?eax?<-?gdt?基地址??????mov?dword?[GdtPtr?+?2],?eax?;?[GdtPtr?+?2]?<-?gdt?基地址????????;?加載?GDTR??????lgdt????[GdtPtr]????????;?關中斷??????cli????????;?打開地址線A20??????in??al,?92h??????or??al,?00000010b??????out?92h,?al????????;?準備切換到保護模式??????mov?eax,?cr0??????or??eax,?1??????mov?cr0,?eax????????;?真正進入保護模式??????jmp?dword?SelectorCode32:0??;?執行這一句會把?SelectorCode32?裝入?cs,?并跳轉到?Code32Selector:0??處????;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;????LABEL_REAL_ENTRY:???????;?從保護模式跳回到實模式就到了這里??????mov?ax,?cs??????mov?ds,?ax??????mov?es,?ax??????mov?ss,?ax????????mov?sp,?[SPValueInRealMode]????????in??al,?92h?????;?┓??????and?al,?11111101b???;?┣?關閉?A20?地址線??????out?92h,?al?????;?┛????????sti?????????;?開中斷????????mov?ax,?4c00h???;?┓??????int?21h?????;?┛回到?DOS??;?END?of?[SECTION?.s16]??????[SECTION?.s32];?32?位代碼段.?由實模式跳入.??[BITS???32]????LABEL_SEG_CODE32:??????mov?ax,?SelectorData??????mov?ds,?ax??????????;?數據段選擇子??????mov?ax,?SelectorVideo??????mov?gs,?ax??????????;?視頻段選擇子????????mov?ax,?SelectorStack??????mov?ss,?ax??????????;?堆棧段選擇子????????mov?esp,?TopOfStack??????????;?下面顯示一個字符串??????mov?ah,?0Ch?????????;?0000:?黑底????1100:?紅字??????xor?esi,?esi??????xor?edi,?edi??????mov?esi,?OffsetPMMessage????;?源數據偏移??????mov?edi,?(80?*?10?+?0)?*?2??;?目的數據偏移。屏幕第?10?行,?第?0?列。??????cld??.1:??????lodsb??????test????al,?al??????jz??.2??????mov?[gs:edi],?ax??????add?edi,?2??????jmp?.1??.2:?;?顯示完畢????????call????DispReturn????????;?Load?TSS??????mov?ax,?SelectorTSS??????ltr?ax??;?在任務內發生特權級變換時要切換堆棧,而內層堆棧的指針存放在當前任務的TSS中,所以要設置任務狀態段寄存器?TR。????????push????SelectorStack3??????push????TopOfStack3??????push????SelectorCodeRing3??????push????0??????retf????????????????;?Ring0?->?Ring3,歷史性轉移!將打印數字?'3'。????;?------------------------------------------------------------------------??DispReturn:??????push????eax??????push????ebx??????mov?eax,?edi??????mov?bl,?160??????div?bl??????and?eax,?0FFh??????inc?eax??????mov?bl,?160??????mul?bl??????mov?edi,?eax??????pop?ebx??????pop?eax????????ret??;?DispReturn?結束---------------------------------------------------------????SegCode32Len????equ?$?-?LABEL_SEG_CODE32??;?END?of?[SECTION?.s32]??????[SECTION?.sdest];?調用門目標段??[BITS???32]????LABEL_SEG_CODE_DEST:??????mov?ax,?SelectorVideo??????mov?gs,?ax??????????;?視頻段選擇子(目的)????????mov?edi,?(80?*?12?+?0)?*?2??;?屏幕第?12?行,?第?0?列。??????mov?ah,?0Ch?????????;?0000:?黑底????1100:?紅字??????mov?al,?'C'??????mov?[gs:edi],?ax????????retf??SegCodeDestLen??equ?$?-?LABEL_SEG_CODE_DEST??;?END?of?[SECTION?.sdest]??????;?16?位代碼段.?由?32?位代碼段跳入,?跳出后到實模式??[SECTION?.s16code]??ALIGN???32??[BITS???16]??LABEL_SEG_CODE16:??????;?跳回實模式:??????mov?ax,?SelectorNormal??????mov?ds,?ax??????mov?es,?ax??????mov?fs,?ax??????mov?gs,?ax??????mov?ss,?ax????????mov?eax,?cr0??????and?al,?11111110b??????mov?cr0,?eax????LABEL_GO_BACK_TO_REAL:??????jmp?0:LABEL_REAL_ENTRY??;?段地址會在程序開始處被設置成正確的值????Code16Len???equ?$?-?LABEL_SEG_CODE16????;?END?of?[SECTION?.s16code]????;?CodeRing3??[SECTION?.ring3]??ALIGN???32??[BITS???32]??LABEL_CODE_RING3:??????mov?ax,?SelectorVideo??????mov?gs,?ax??????????;?視頻段選擇子(目的)????????mov?edi,?(80?*?14?+?0)?*?2??;?屏幕第?14?行,?第?0?列。??????mov?ah,?0Ch?????????;?0000:?黑底????1100:?紅字??????mov?al,?'3'??????mov?[gs:edi],?ax????????call????SelectorCallGateTest:0??;?測試調用門(有特權級變換),將打印字母?'C'。??????jmp?$??SegCodeRing3Len?equ?$?-?LABEL_CODE_RING3??;?END?of?[SECTION?.ring3]??
83—117初始化任務狀態堆棧段(TSS)
292—300 通過使用retf完成從Ring0-->Ring3的跳轉,即高特權級跳轉到低特權級,跳轉到LABEL_CODE_RING3。
380—380 通過調用門,完成從Ring3-->Ring0的跳轉,即低特權級跳轉到高特權級,跳轉到LABEL_SEG_CODE_DEST
336—336 通過retf,完成從Ring0-->Ring3的跳轉,即高特權級跳轉到低特權級,跳轉到379。
到目前為止,我們已經實現了兩次從高特權級到低特權級以及一次從低特權級到高特權級的轉移,最終在低特權級的代碼中讓程序停住。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀
總結
以上是生活随笔為你收集整理的不同特权级代码段之间的跳转的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。