對新型CPU快速系統(tǒng)調(diào)用的支持_第1頁
對新型CPU快速系統(tǒng)調(diào)用的支持_第2頁
對新型CPU快速系統(tǒng)調(diào)用的支持_第3頁
對新型CPU快速系統(tǒng)調(diào)用的支持_第4頁
對新型CPU快速系統(tǒng)調(diào)用的支持_第5頁
已閱讀5頁,還剩6頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、2 6 對新型 CPU 快速系統(tǒng)調(diào)用的支持Linux 2.6對新型CPU快速系統(tǒng)調(diào)用的支持2011-03-22 16:58在Linux 2.4內(nèi)核中,用戶態(tài)Ring3代碼請求內(nèi)核態(tài)Ring0代碼完成某些功能是通過系統(tǒng)調(diào)用完成的,而系統(tǒng)調(diào)用的是通過軟中斷指令(int 0x80)實現(xiàn)的。在x86保護(hù)模式中,處理INT中斷指令時,CPU首先從中斷描述表IDT取出對應(yīng)的門描述符,判斷門描述符的種類,然后檢查門描述符的級別DPL和INT指令調(diào)用者的級別CPL,當(dāng)CPL=DPL也就是說INT調(diào)用者級別高于描述符指定級別時,才能成功調(diào)用,最后再根據(jù)描述符的內(nèi)容,進(jìn)行壓棧、跳轉(zhuǎn)、權(quán)限級別提升。內(nèi)核代碼執(zhí)行完畢

2、之后,調(diào)用IRET指令返回,IRET指令恢復(fù)用戶棧,并跳轉(zhuǎn)會低級別的代碼。其實,在發(fā)生系統(tǒng)調(diào)用,由Ring3進(jìn)入Ring0的這個過程浪費(fèi)了不少的CPU周期,例如,系統(tǒng)調(diào)用必然需要由Ring3進(jìn)入Ring0(由內(nèi)核調(diào)用INT指令的方式除外,這多半屬于Hacker的內(nèi)核模塊所為),權(quán)限提升之前和之后的級別是固定的,CPL肯定是3,而INT 80的DPL肯定也是3,這樣CPU檢查門描述符的DPL和調(diào)用者的CPL就是完全沒必要。正是由于如此,Intel x86 CPU從PII 300(Family 6,Model 3,Stepping 3)之后,開始支持新的系統(tǒng)調(diào)用指令sysenter/sysexit

3、。sysenter指令用于由Ring3進(jìn)入Ring0,SYSEXIT指令用于由Ring0返回Ring3。由于沒有特權(quán)級別檢查的處理,也沒有壓棧的操作,所以執(zhí)行速度比INT n/IRET快了不少。下面是一些來自互聯(lián)網(wǎng)的有關(guān)sysenter/sysexit指令和INT n/IRET指令在Intel Pentium CPU上的性能對比:表1:系統(tǒng)調(diào)用性能測試測試硬件:Intel Pentium III CPU,450 MHzProcessor Family:6 Model:7 Stepping:2用戶模式花費(fèi)的時間核心模式花費(fèi)的時間基于sysenter/sysexit指令的系統(tǒng)調(diào)用9.833 mic

4、roseconds6.833 microseconds基于中斷INT n指令的系統(tǒng)調(diào)用17.500 microseconds7.000 microseconds數(shù)據(jù)來源:1數(shù)據(jù)來源:2表2:各種CPU上INT 0x80和SYSENTER執(zhí)行速度的比較CPUInt0x80sysenter Athlon XP 1600+277169 800MHz mode 1athlon 279170 2.8GHz p4 northwood ht 1152442上述數(shù)據(jù)為對100000次getppid()系統(tǒng)調(diào)用所花費(fèi)的CPU時鐘周期取的平均值數(shù)據(jù)來源3自這種技術(shù)推出之后,人們一直在考慮在Linux中加入對這種指

5、令的支持,在K的郵件列表中,主題為Intel P6 vs P7 system call performance的大量郵件討論了采用這種指令的必要性,郵件中列舉的理由主要是Intel在Pentium 4的設(shè)計上存在問題,造成Pentium 4使用中斷方式執(zhí)行的系統(tǒng)調(diào)用比Pentium 3以及AMD Athlon所耗費(fèi)的CPU時鐘周期多上510倍。因此,在Pentium 4平臺上,通過sysenter/sysexit指令來執(zhí)行系統(tǒng)調(diào)用已經(jīng)是刻不容緩的需求。在Intel的軟件開發(fā)者手冊第二、三卷(Vol.2B,Vol.3)中,4.8.7節(jié)是關(guān)于sysenter/sysexit指令的

6、詳細(xì)描述。手冊中說明,sysenter指令可用于特權(quán)級3的用戶代碼調(diào)用特權(quán)級0的系統(tǒng)內(nèi)核代碼,而SYSEXIT指令則用于特權(quán)級0的系統(tǒng)代碼返回用戶空間中。sysenter指令可以在3,2,1這三個特權(quán)級別調(diào)用(Linux中只用到了特權(quán)級3),而SYSEXIT指令只能從特權(quán)級0調(diào)用。執(zhí)行sysenter指令的系統(tǒng)必須滿足兩個條件:1.目標(biāo)Ring 0代碼段必須是平坦模式(Flat Mode)的4GB的可讀可執(zhí)行的非一致代碼段。2.目標(biāo)RING0堆棧段必須是平坦模式(Flat Mode)的4GB的可讀可寫向上擴(kuò)展的棧段。在Intel的手冊中,還提到了sysenter/sysexit和int n/i

7、ret指令的一個區(qū)別,那就是sysenter/sysexit指令并不成對,sysenter指令并不會把SYSEXIT所需的返回地址壓棧,sysexit返回的地址并不一定是sysenter指令的下一個指令地址。調(diào)用sysenter/sysexit指令地址的跳轉(zhuǎn)是通過設(shè)置一組特殊寄存器實現(xiàn)的。這些寄存器包括:SYSENTER_CS_MSR-用于指定要執(zhí)行的Ring 0代碼的代碼段選擇符,由它還能得出目標(biāo)Ring 0所用堆棧段的段選擇符;SYSENTER_EIP_MSR-用于指定要執(zhí)行的Ring 0代碼的起始地址;SYSENTER_ESP_MSR-用于指定要執(zhí)行的Ring 0代碼所使用的棧指針這些寄

8、存器可以通過wrmsr指令來設(shè)置,執(zhí)行wrmsr指令時,通過寄存器edx、eax指定設(shè)置的值,edx指定值的高32位,eax指定值的低32位,在設(shè)置上述寄存器時,edx都是0,通過寄存器ecx指定填充的MSR寄存器,sysenter_CS_MSR、sysenter_ESP_MSR、sysenter_EIP_MSR寄存器分別對應(yīng)0x174、0x175、0x176,需要注意的是,wrmsr指令只能在Ring 0執(zhí)行。這里還要介紹一個特性,就是Ring0、Ring3的代碼段描述符和堆棧段描述符在全局描述符表GDT中是順序排列的,這樣只需知道SYSENTER_CS_MSR中指定的Ring0的代碼段描述

9、符,就可以推算出Ring0的堆棧段描述符以及Ring3的代碼段描述符和堆棧段描述符。在Ring3的代碼調(diào)用了sysenter指令之后,CPU會做出如下的操作:1.將SYSENTER_CS_MSR的值裝載到cs寄存器2.將SYSENTER_EIP_MSR的值裝載到eip寄存器3.將SYSENTER_CS_MSR的值加8(Ring0的堆棧段描述符)裝載到ss寄存器。4.將SYSENTER_ESP_MSR的值裝載到esp寄存器5.將特權(quán)級切換到Ring0 6.如果EFLAGS寄存器的VM標(biāo)志被置位,則清除該標(biāo)志7.開始執(zhí)行指定的Ring0代碼在Ring0代碼執(zhí)行完畢,調(diào)用SYSEXIT指令退回Rin

10、g3時,CPU會做出如下操作:1.將SYSENTER_CS_MSR的值加16(Ring3的代碼段描述符)裝載到cs寄存器2.將寄存器edx的值裝載到eip寄存器3.將SYSENTER_CS_MSR的值加24(Ring3的堆棧段描述符)裝載到ss寄存器4.將寄存器ecx的值裝載到esp寄存器5.將特權(quán)級切換到Ring3 6.繼續(xù)執(zhí)行Ring3的代碼由此可知,在調(diào)用SYSENTER進(jìn)入Ring0之前,一定需要通過wrmsr指令設(shè)置好Ring0代碼的相關(guān)信息,在調(diào)用SYSEXIT之前,還要保證寄存器edx、ecx的正確性。根據(jù)Intel的CPU手冊,我們可以通過CPUID指令來查看CPU是否支持sy

11、senter/sysexit指令,做法是將EAX寄存器賦值1,調(diào)用CPUID指令,寄存器edx中第11位(這一位名稱為SEP)就表示是否支持。在調(diào)用CPUID指令之后,還需要查看CPU的Family、Model、Stepping屬性來確認(rèn),因為據(jù)稱Pentium Pro處理器會報告SEP但是卻不支持sysenter/sysexit指令。只有Family大于等于6,Model大于等于3,Stepping大于等于3的時候,才能確認(rèn)CPU支持sysenter/sysexit指令。在2.4內(nèi)核中,直到最近的發(fā)布的2.4.26-rc2版本,沒有加入對sysenter/sysexit指令的支持。而對sys

12、enter/sysexit指令的支持最早是2002年,由Linus Torvalds編寫并首次加入2.5版內(nèi)核中的,經(jīng)過多方測試和多次patch,最終正式加入到了2.6版本的內(nèi)核中。具體談到系統(tǒng)調(diào)用的完成,不能孤立的看內(nèi)核的代碼,我們知道,系統(tǒng)調(diào)用多被封裝成庫函數(shù)提供給應(yīng)用程序調(diào)用,應(yīng)用程序調(diào)用庫函數(shù)后,由glibc庫負(fù)責(zé)進(jìn)入內(nèi)核調(diào)用系統(tǒng)調(diào)用函數(shù)。在2.4內(nèi)核加上老版的glibc的情況下,庫函數(shù)所做的就是通過int指令來完成系統(tǒng)調(diào)用,而內(nèi)核提供的系統(tǒng)調(diào)用接口很簡單,只要在IDT中提供INT 0x80的入口,庫就可以完成中斷調(diào)用。在2.6內(nèi)核中,內(nèi)核代碼同時包含了對int 0x80中斷方式和sy

13、senter指令方式調(diào)用的支持,因此內(nèi)核會給用戶空間提供一段入口代碼,內(nèi)核啟動時根據(jù)CPU類型,決定這段代碼采取哪種系統(tǒng)調(diào)用方式。對于glibc來說,無需考慮系統(tǒng)調(diào)用方式,直接調(diào)用這段入口代碼,即可完成系統(tǒng)調(diào)用。這樣做還可以盡量減少對glibc的改動,在glibc的源碼中,只需將intmessagex80指令替換成call入口地址即可。下面,以2.6.0的內(nèi)核代碼配合支持SYSENTER調(diào)用方式的glibc2.3.3為例,分析一下系統(tǒng)調(diào)用的具體實現(xiàn)。前面說到的這段入口代碼,根據(jù)調(diào)用方式分為兩個文件,支持sysenter指令的代碼包含在文件arch/i386/kernel/vsyscall-sy

14、senter.S中,支持int中斷的代碼包含在arch/i386/kernel/vsyscall-int80.S中,入口名都是_kernel_vsyscall,這兩個文件編譯出的二進(jìn)制代碼由arch/i386/kernel/vsyscall.S所包含,并導(dǎo)出起始地址和結(jié)束地址。2.6內(nèi)核在啟動的時候,調(diào)用了新增的函數(shù)sysenter_setup(參見arch/i386/kernel/sysenter.c),在這個函數(shù)中,內(nèi)核將虛擬內(nèi)存空間的頂端一個固定地址頁面(從0xffffe000開始到0xffffeffff的4k大小)映射到一個空閑的物理內(nèi)存頁面。然后通過之前執(zhí)行CPUID的指令得到的數(shù)據(jù)

15、,檢測CPU是否支持sysenter/sysexit指令。如果CPU不支持,那么將采用INT調(diào)用方式的入口代碼拷貝到這個頁面中,然后返回。相反,如果CPU支持SYSETER/SYSEXIT指令,則將采用SYSENTER調(diào)用方式的入口代碼拷貝到這個頁面中。使用宏on_each_cpu在每個CPU上執(zhí)行enable_sep_cpu這個函數(shù)。在enable_sep_cpu函數(shù)中,內(nèi)核將當(dāng)前CPU的TSS結(jié)構(gòu)中的ss1設(shè)置為當(dāng)前內(nèi)核使用的代碼段,esp1設(shè)置為該TSS結(jié)構(gòu)中保留的一個256字節(jié)大小的堆棧。在X86中,TSS結(jié)構(gòu)中ss1和esp1本來是用于保存Ring 1進(jìn)程的堆棧段和堆棧指針的。由于內(nèi)

16、核在啟動時,并不能預(yù)知調(diào)用sysenter指令進(jìn)入Ring 0后esp的確切值,而應(yīng)用程序又無權(quán)調(diào)用wrmsr指令動態(tài)設(shè)置,所以此時就借用esp1指向一個固定的緩沖區(qū)來填充這個MSR寄存器,由于Ring 1根本沒被啟用,所以并不會對系統(tǒng)造成任何影響。在下面的文章中會介紹進(jìn)入Ring 0之后,內(nèi)核如何修復(fù)ESP來指向正確的Ring 0堆棧。關(guān)于TSS結(jié)構(gòu)更細(xì)節(jié)的應(yīng)用可參考代碼include/asm-i386/processor.h)。然后,內(nèi)核通過wrmsr(msr,val1,val2)宏調(diào)用wrmsr指令對當(dāng)前CPU設(shè)置MSR寄存器,可以看出調(diào)用宏的第三個參數(shù)即edx都被設(shè)置為0。其中SYSE

17、NTER_CS_MSR的值被設(shè)置為當(dāng)前內(nèi)核用的所在代碼段;SYSENTER_ESP_MSR被設(shè)置為esp1,即指向當(dāng)前CPU的TSS結(jié)構(gòu)中的堆棧;SYSENTER_EIP_MSR則被設(shè)置為內(nèi)核中處理sysenter指令的接口函數(shù)sysenter_entry(參見arch/i386/kernel/entry.S)。這樣,sysenter指令的準(zhǔn)備工作就完成了。通過內(nèi)核在啟動時進(jìn)行這樣的設(shè)置,在每個進(jìn)程的進(jìn)程空間中,都能訪問到內(nèi)核所映射的這個代碼頁面,當(dāng)然這個頁面對于應(yīng)用程序來說是只讀的。我們通過新版的ldd工具查看任意一個可執(zhí)行程序,可以看到下面的結(jié)果:roottest# dynamic:ELF

18、 32-bit LSB executable,Intel 80386,version 1(SYSV),for GNU/Linux 2.2.5,dynamically linked(uses shared libs),not strippedroottest#ldd dynamic linux-gate.so.1=(0xffffe000)libc.so.6=/lib/tls/libc.so.6(0x4002c000)/lib/ld-linux.so.2=/lib/ld-linux.so.2(0x 40000000)這個所謂的linux-gate.so.1的內(nèi)容就是內(nèi)核映射的代碼,系統(tǒng)中其實并不存

19、在這樣一個鏈接庫文件,它的名字是由ldd自己起的,而在老版本的ldd中,雖然能夠檢測到這段代碼,但是由于沒有命名而且在系統(tǒng)中找不到對應(yīng)鏈接庫文件,所以會有一些顯示上的問題。有關(guān)這個問題的背景,可以參考下面這個網(wǎng)址:。為了配合內(nèi)核使用新的系統(tǒng)調(diào)用方式,glibc中要做一定的修改。新的glibc-2.3.2(及其以后版本中)中已經(jīng)包含了這個改動,在glibc源代碼的sysdeps/unix/sysv/linux/i386/sysdep.h文件中,處理系統(tǒng)調(diào)用的宏INTERNAL_SYSCALL在不同的編譯選項下有不同的結(jié)果。在打開支持sysenter/sysexit指令的選項I386_USE_SY

20、SENTER下,系統(tǒng)調(diào)用會有兩種方式,在靜態(tài)鏈接(編譯時加上-static選項)情況下,采用call*_dl_sysinfo指令;在動態(tài)鏈接情況下,采用call*%gs:0x10指令。這兩種情況由glibc庫采用哪種方法鏈接,實際上最終都相當(dāng)于調(diào)用某個固定地址的代碼。下面我們通過一個小小的程序,配合gdb來驗證。首先是一個靜態(tài)編譯的程序,代碼很簡單:main()getuid();將代碼加上static選項用gcc靜態(tài)編譯,然后用gdb裝載并反編譯main函數(shù)。roottest opt#gcc test.c-o./static-staticroottest opt#gdb./static(gdb

21、)disassemble main0x 08048204 main+0:push%ebp 0x 08048205 main+1:mov%esp,%ebp 0x 08048207 main+3:submessagex8,%esp 0x 0804820a main+6:andmessagexfffffff0,%esp 0x 0804820d main+9:movmessagex0,%eax 0x 08048212 main+14:sub%eax,%esp 0x 08048214 main+16:call 0x804cb20 _getuid 0x 08048219 main+21:leave0x 0

22、804821a main+22:ret可以看出,main函數(shù)中調(diào)用了_getuid函數(shù),接著反編譯_getuid函數(shù)。(gdb)disassemble 0x804cb200x0804cb20 _getuid+0:push%ebp 0x0804cb21 _getuid+1:mov 0x80aa028,%eax 0x0804cb26 _getuid+6:mov%esp,%ebp 0x0804cb28 _getuid+8:test%eax,%eax 0x0804cb2a _getuid+10:jle 0x804cb40 _getuid+32 0x0804cb2c _getuid+12:movmess

23、agex18,%eax 0x0804cb31 _getuid+17:call*0x80aa054 0x0804cb37 _getuid+23:pop%ebp 0x0804cb38 _getuid+24:ret上面只是_getuid函數(shù)的一部分??梢钥吹絖getuid將eax寄存器賦值為getuid系統(tǒng)調(diào)用的功能號0x18然后調(diào)用了另一個函數(shù),這個函數(shù)的入口在哪里呢?接著查看位于地址0x80aa054的值。(gdb)X 0x80aa0540x80aa054 _dl_sysinfo:0x0804d7f6看起來不像是指向內(nèi)核映射頁面內(nèi)的代碼,但是,可以確認(rèn),_dl_sysinfo指針的指向的地址就是

24、0x80aa054。下面,我們試著啟動這個程序,然后停在程序第一條語句,再查看這個地方的值。(gdb)b mainBreakpoint 1at 0x 804820a(gdb)rStarting program:/opt/static Breakpoint 1,0x 0804820a in main()(gdb)X 0x80aa054 0x80aa054 _dl_sysinfo:0xffffe400可以看到,_dl_sysinfo指針指向的數(shù)值已經(jīng)發(fā)生了變化,指向了0xffffe400,如果我們繼續(xù)運(yùn)行程序,_getuid函數(shù)將會調(diào)用地址0xffffe400處的代碼。接下來,我們將上面的代碼編譯

25、成動態(tài)鏈接的方式,即默認(rèn)方式,用gdb裝載并反編譯main函數(shù)roottest opt#gcc test.c-o./dynamicroottest opt#gdb./dynamic(gdb)disassemble main0x 08048204 main+0:push%ebp 0x 08048205 main+1:mov%esp,%ebp 0x 08048207 main+3:submessagex8,%esp 0x 0804820a main+6:andmessagexfffffff0,%esp 0x 0804820d main+9:movmessagex0,%eax 0x 08048212

26、 main+14:sub%eax,%esp 0x 08048214 main+16:call 0x 8048288 0x 08048219 main+21:leave0x 0804821a main+22:ret由于libc庫是在程序初始化時才被裝載,所以我們先啟動程序,并停在main第一條語句,然后反匯編getuid庫函數(shù)(gdb)b mainBreakpoint 1at 0x 804820a(gdb)rStarting program:/opt/dynamic Breakpoint 1,0x 0804820a in main()(gdb)disassemble getuid Dump of

27、 assembler code for function getuid:0x40219e50 _getuid+0:push%ebp 0x40219e51 _getuid+1:mov%esp,%ebp 0x40219e53 _getuid+3:push%ebx 0x40219e54 _getuid+4:call 0x40219e59 _getuid+9 0x40219e59 _getuid+9:pop%ebx 0x40219e5a _getuid+10:addmessagex84b0f,%ebx 0x40219e60 _getuid+16:mov 0xffffd87c(%ebx),%eax 0x

28、40219e66 _getuid+22:test%eax,%eax 0x40219 e68 _getuid+24:jle 0x40219e80 _getuid+48 0x40219e6a _getuid+26:movmessagex18,%eax 0x40219e6f _getuid+31:call*%gs:0x10 0x40219e76 _getuid+38:pop%ebx 0x40219e77 _getuid+39:pop%ebp 0x40219e78 _getuid+40:ret可以看出,庫函數(shù)getuid將eax寄存器設(shè)置為getuid系統(tǒng)調(diào)用的調(diào)用號0x18,然后調(diào)用%gs:0x10

29、所指向的函數(shù)。在gdb中,無法查看非DS段的數(shù)據(jù)內(nèi)容,所以無法查看%gs:0x10所保存的實際數(shù)值,不過我們可以通過編程的辦法,內(nèi)嵌匯編將%gs:0x10的值賦予某個局部變量來得到這個數(shù)值,而這個數(shù)值也是0xffffe400,具體代碼這里就不再贅述。由此可見,無論是靜態(tài)還是動態(tài)方式,最終我們都來到了0xffffe400這里的一段代碼,這里就是內(nèi)核為我們映射的系統(tǒng)調(diào)用入口代碼。在gdb中,我們可以直接反匯編來查看這里的代碼(gdb)disassemble 0xffffe400 0xffffe414 Dump of assembler code from 0xffffe400 to 0xffffe

30、414:0xffffe400:push%ecx 0xffffe401:push%edx0xffffe402:push%ebp 0xffffe403:mov%esp,%ebp0xffffe405:sysenter0xffffe407:nop 0xffffe408:nop0xffffe409:nop0xffffe40a:nop0xffffe40b:nop 0xffffe40c:nop0xffffe40d:nop0xffffe40e:jmp 0xffffe403 0xffffe410:pop%ebp0xffffe411:pop%edx 0xffffe412:pop%ecx0xffffe413:ret

31、End of assembler dump.這段代碼正是arch/i386/kernel/vsyscall-sysenter.S文件中的代碼。其中,在sysenter之前的是入口代碼,在0xffffe410開始的是內(nèi)核返回處理代碼(后面提到的SYSENTER_RETURN即指向這里)。在入口代碼中,首先是保存當(dāng)前的ecx,edx(由于sysexit指令需要使用這兩個寄存器)以及ebp。然后調(diào)用sysenter指令,跳轉(zhuǎn)到內(nèi)核Ring 0代碼,也就是sysenter_entry入口處。sysenter_entry整個的實現(xiàn)可以參見arch/i386/kernel/entry.S。內(nèi)核處理SYSE

32、NTER的代碼和處理INT的代碼不太一樣。通過sysenter指令進(jìn)入Ring 0之后,由于當(dāng)前的ESP并非指向正確的內(nèi)核棧,而是當(dāng)前CPU的TSS結(jié)構(gòu)中的一個緩沖區(qū)(參見上文),所以首先要解決的是修復(fù)ESP,幸運(yùn)的是,TSS結(jié)構(gòu)中ESP0成員本身就保存有Ring 0狀態(tài)的ESP值,所以在這里將TSS結(jié)構(gòu)中ESP0的值賦予ESP寄存器。將ESP恢復(fù)成指向正確的堆棧之后,由于SYSENTER不是通過調(diào)用門進(jìn)入Ring 0,所以在堆棧中的上下文和使用INT指令的不一樣,INT指令進(jìn)入Ring 0后棧中會保存如下的值。返回用戶態(tài)的EIP用戶態(tài)的CS用戶態(tài)的EFLAGS用戶態(tài)的ESP用戶態(tài)的SS(和D

33、S相同)因此,為了簡化和重用代碼,內(nèi)核會用pushl指令往棧中放入上述各值,值得注意的是,內(nèi)核在棧中放入的相對應(yīng)用戶態(tài)EIP的值,是一個代碼標(biāo)簽SYSENTER_RETURN,在vsyscall-sysenter.S可以看到,它就在sysenter指令的后面(在它們之間,有一段NOP,是內(nèi)核返回出錯時的處理代碼)。接下來,處理系統(tǒng)調(diào)用的代碼就和中斷方式的處理代碼一模一樣了,內(nèi)核保存所有的寄存器,然后系統(tǒng)調(diào)用表找到對應(yīng)系統(tǒng)調(diào)用的入口,完成調(diào)用。最后,內(nèi)核從棧中取出前面存入的用戶態(tài)的EIP和ESP,存入edx和ecx寄存器,調(diào)用SYSEXIT指令返回用戶態(tài)。返回用戶態(tài)之后,從棧中取出ESP,edx,ecx,最終返回glibc庫。值得一提的是,從Windows XP開始,Windows的系統(tǒng)調(diào)用方式也從軟中斷int 0x2e轉(zhuǎn)換到采用sysenter方式,由于完全不再支持int方式,因此Windows XP的對CPU的最低配置要求是PentiumII 300MHz。在其它的操作系統(tǒng)例如*BSD系列,目前并沒有提供對sysenter指令的支持。在CPU方面,AMD的CPU支持一套與之對應(yīng)的指令SYSCALL/SYSRET。在純32位的AMD CPU上,還沒有支持sysente

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論