freepeople性欧美熟妇, 色戒完整版无删减158分钟hd, 无码精品国产vα在线观看DVD, 丰满少妇伦精品无码专区在线观看,艾栗栗与纹身男宾馆3p50分钟,国产AV片在线观看,黑人与美女高潮,18岁女RAPPERDISSSUBS,国产手机在机看影片

正文內(nèi)容

[計(jì)算機(jī)軟件及應(yīng)用]第10章系統(tǒng)調(diào)用(已修改)

2025-10-23 23:18 本頁面
 

【正文】 第 10章系統(tǒng)調(diào)用 本章對 Linux系統(tǒng)調(diào)用的定義、基本原理、使用方法和注意事項(xiàng)作了概括的介紹,以便讀者對 Linux系統(tǒng)調(diào)用建立一個大致的印象。較詳細(xì)地討論了系統(tǒng)調(diào)用 wait、waitpid和 exec函數(shù)族,并通過兩個實(shí)際例子來說明系統(tǒng)調(diào)用。 系統(tǒng)調(diào)用概述 ? 所有的操作系統(tǒng)都提供多種服務(wù)的入口點(diǎn),由此程序向內(nèi)核請求服務(wù)。各種版本的Unix都提供經(jīng)良好定義的有限數(shù)目的入口點(diǎn),經(jīng)過這些入口點(diǎn)進(jìn)入內(nèi)核,這些入口點(diǎn)被稱為系統(tǒng)調(diào)用 (system call)。系統(tǒng)調(diào)用是不能更改的一種 Unix特征。 系統(tǒng)調(diào)用過程 圖 系統(tǒng)調(diào)用過程示意圖 ? Linux內(nèi)核中設(shè)置了一組用于實(shí)現(xiàn)各種系統(tǒng)功能的子程序,稱為系統(tǒng)調(diào)用。用戶可以通過系統(tǒng)調(diào)用命令在自己的應(yīng)用程序中調(diào)用它們。從某種角度來看,系統(tǒng)調(diào)用和普通的函數(shù)調(diào)用非常相似。區(qū)別僅僅在于,系統(tǒng)調(diào)用由操作系統(tǒng)核心提供,運(yùn)行于核心態(tài);而普通的函數(shù)調(diào)用由函數(shù)庫或用戶自己提供,運(yùn)行于用戶態(tài)。二者在使用方式上也有相似之處。 ? 隨 Linux核心還提供了一些 C語言函數(shù)庫,這些庫對系統(tǒng)調(diào)用進(jìn)行了一些包裝和擴(kuò)展,因?yàn)檫@些庫函數(shù)與系統(tǒng)調(diào)用的關(guān)系非常緊密,所以習(xí)慣上把這些函數(shù)也稱為系統(tǒng)調(diào)用。 ? 在 Linux中,系統(tǒng)調(diào)用的過程大體如圖 : ? 一般來說, CPU硬件決定了進(jìn)程不能訪問內(nèi)核所占內(nèi)存空間也不能調(diào)用內(nèi)核函數(shù),這被稱作 保護(hù)模式 。系統(tǒng)調(diào)用是這些規(guī)則的一個例外。系統(tǒng)調(diào)用的原理是:進(jìn)程先用適當(dāng)?shù)闹堤畛浼拇嫫?,然后調(diào)用一個特殊的指令跳轉(zhuǎn)一個事先定義的內(nèi)核中的一個位置(當(dāng)然,這個位置是用戶進(jìn)程可讀但是不可寫的)。硬件知道一旦跳到這個位置,就不是在限制模式下運(yùn)行的用戶,而是作為操作系統(tǒng)的內(nèi)核。在 Intel CPU中,這個指令由中斷0x80實(shí)現(xiàn)。 ? 進(jìn)程可以跳轉(zhuǎn)到的內(nèi)核位置叫做sysem_call。這個過程檢查系統(tǒng)調(diào)用號,該號碼告訴內(nèi)核進(jìn)程請求哪種服務(wù)。然后內(nèi)核進(jìn)程查看系統(tǒng)調(diào)用表 (sys_call_table)找到所調(diào)用的內(nèi)核函數(shù)入口地址。接著調(diào)用相應(yīng)的函數(shù),在返回后做一些系統(tǒng)檢查,最后返回到進(jìn)程(如果這個進(jìn)程時間用盡,則返回到其他進(jìn)程)。 sysem_call的代碼在源碼 /kernel/Entry(system_call)的下一行。 ? 實(shí)際上,很多已經(jīng)被習(xí)以為常的 C語言標(biāo)準(zhǔn)函數(shù),在 Linux平臺上的實(shí)現(xiàn)都是靠系統(tǒng)調(diào)用完成的,所以如果想對系統(tǒng)底層的原理作深入的了解,掌握各種系統(tǒng)調(diào)用是初步的要求。 Linux下編程高手,其標(biāo)志之一也是能對各種系統(tǒng)調(diào)用有透徹的了解。 ? 在很多情況下,系統(tǒng)調(diào)用是實(shí)現(xiàn)編程想法的簡潔有效的途徑,所以應(yīng)該盡量多掌握一些系統(tǒng)調(diào)用,這會對程序設(shè)計(jì)過程帶來意想不到的幫助。 系統(tǒng)調(diào)用的進(jìn)入 ? 系統(tǒng)調(diào)用的進(jìn)入可分為 “ 用戶程序調(diào)用系統(tǒng)調(diào)用總控程序 (system_call)”和 “ 系統(tǒng)調(diào)用總控程序調(diào)用各個服務(wù)程序 ” 兩部分;下面將分別對這兩個部分進(jìn)行詳細(xì)說明: ? ( 1) “ 用戶程序調(diào)用系統(tǒng)調(diào)用總控程序 ” 的實(shí)現(xiàn):Linux的系統(tǒng)調(diào)用使用第 0x80號中斷向量項(xiàng)作為總的入口,即系統(tǒng)調(diào)用總控程序的入口地址system_call就掛在中斷 0x80上。也就是說,只要用戶程序執(zhí)行 0x80中斷 ( int 0x80 ),就可實(shí)現(xiàn) “ 用戶程序 系統(tǒng)調(diào)用總控程序 ” 的進(jìn)入。只是0x80中斷的執(zhí)行語句 int 0x80 被封裝在標(biāo)準(zhǔn) C庫中,用戶程序只需用標(biāo)準(zhǔn)系統(tǒng)調(diào)用函數(shù)就可以了,而不需要在用戶程序中直接寫 0x80中斷的執(zhí)行語句 int 0x80。中斷的進(jìn)入的詳細(xì)過程可參見第 3章 “ 中斷和中斷處理 ” 。 ? ( 2在系統(tǒng)調(diào)用總控程序中,通過語句 “ call * SYMBOL_NAME(sys_call_table)(,%eax,4)”來調(diào)用各個服務(wù)程序( SYMBOL_NAME是定義在/include/linux/: define SYMBOL_NAME_LABEL(X) X),可以忽略)。當(dāng)系統(tǒng)調(diào)用總控程序執(zhí)行到此語句時, eax中的內(nèi)容即是相應(yīng)系統(tǒng)調(diào)用的編號,此編號即相應(yīng)服務(wù)程序在系統(tǒng)調(diào)用向量表sys_call_table中的編號(系統(tǒng)調(diào)用的編號的有關(guān)說明在/linux/include/asm/)。又因?yàn)橄到y(tǒng)調(diào)用向量表 sys_call_table每項(xiàng)占 4個字節(jié),所以由 %eax 乘上4形成偏移地址,而 sys_call_table則為基址;基址加上偏移所指向的內(nèi)容就是相應(yīng)系統(tǒng)調(diào)用服務(wù)程序的入口地址。所以此 call語句就相當(dāng)于直接調(diào)用對應(yīng)的系統(tǒng)調(diào)用服務(wù)程序。 ? 在 Linux中所有系統(tǒng)調(diào)用服務(wù)例程都使用了 asmlinkage標(biāo)志。此標(biāo)志是一個定義在 /include/linux/ 中的一個宏: if defined __i386__ amp。amp。 (__GNUC__ 2 || __GNUC_MINOR__ 7) define asmlinkage CPP_ASMLINKAGE__attribute__((regparm(0))) else define asmlinkage CPP_ASMLINKAGE endif ? 其中涉及到了 gcc的一些約定,總之,這個標(biāo)志它可以告訴編譯器該函數(shù)不需要從寄存器中獲得任何參數(shù),而是從堆棧中取得參數(shù);即參數(shù)在堆棧中傳遞,而不是直接通過寄存器; ? 堆棧參數(shù)如下: EBX = 0x00 ECX = 0x04 EDX = 0x08 ESI = 0x0C EDI = 0x10 EBP = 0x14 EAX = 0x18 DS = 0x1C ES = 0x20 ORIG_EAX = 0x24 EIP = 0x28 CS = 0x2C EFLAGS = 0x30 ? 在進(jìn)入系統(tǒng)調(diào)用總控程序前,用戶按照以上的對應(yīng)順序?qū)?shù)放到對應(yīng)寄存器中,在系統(tǒng)調(diào)用總控程序一開始就將這些寄存器壓入堆棧;在退出總控程序前又按如上順序堆棧;用戶程序則可以直接從寄存器中復(fù)得被服務(wù)程序加工過了的參數(shù)。而對于系統(tǒng)調(diào)用服務(wù)程序而言,參數(shù)就可以直接從總控程序壓入的堆棧中復(fù)得;對參數(shù)的修改一可以直接在堆棧中進(jìn)行;其實(shí),這就是asmlinkage標(biāo)志的作用。所以在進(jìn)入和退出系統(tǒng)調(diào)用總控程序時, “ 保護(hù)現(xiàn)場 ” 和 “ 恢復(fù)現(xiàn)場 ”的內(nèi)容并不一定會相同。 ? ( 3)特殊的服務(wù)程序:在 Linux內(nèi)核中,有好幾個系統(tǒng)調(diào)用的服務(wù)程 序都是定義在 /usr/src/linux/kernel/ 中的同一個函數(shù): asmlinkage int sys_ni_syscall(void) { return ENOSYS; } ? 此函數(shù)除了返回錯誤號之外,什么都沒干。其作用歸結(jié)起來有如下三種可能: ( 1) 處理邊界錯誤, 0號系統(tǒng)調(diào)用就是用的此特殊的服務(wù)程序; ( 2) 用來替換舊的已淘汰了的系統(tǒng)調(diào)用,如: Nr 17, Nr 31, Nr 32, Nr 35, Nr 44, Nr 53, Nr 56, Nr58, Nr 98; ( 3) 用于將要擴(kuò)展的系統(tǒng)調(diào)用,如: Nr 137, Nr 188, Nr 189; 系統(tǒng)調(diào)用總控程序 ? 系統(tǒng)調(diào)用總控程序 (system_call)可參見arch/i386/kernel/,其執(zhí)行流程如圖 : 圖 調(diào)用總控程序 (system_call)執(zhí)行流程圖 一個簡單的系統(tǒng)調(diào)用例子 ? 系統(tǒng)調(diào)用是 CPU主動地、同步地進(jìn)入系統(tǒng)空間的手段。系統(tǒng)調(diào)用只能發(fā)生在用戶空間。 Linux下的系統(tǒng)調(diào)用是通過中斷指令“ INT 0x80”實(shí)現(xiàn)的。 ? 下面以 sethostname()這個簡單的系統(tǒng)調(diào)用作為例子,介紹系統(tǒng)調(diào)用中進(jìn)入內(nèi)核空間,以及完成了服務(wù)返回用戶空間的過程。 ? int sethostname(const char *name,size_t len)。 ? 參數(shù) name是要設(shè)置的主機(jī)名,而 len是該字符串的長度。調(diào)用返回 0表示成功,- 1表示失敗。失敗時可從全局變量 errno 中得到具體的出錯代碼。通過反匯編 : : file format elf32i386 Disassembly of section. text: 00000000 0:89 da mov1 %ebx,%edx 2:8b 4c 24 08 mov1 0x8(%esp,1),%ecx 6:8b 5c 24 04 mov1 0x4(%esp,1),%ebx a:b8 4a 00 00 00 mov1 $0x4a,%eax f:cd 80 int $0x80 11:89 d3 mov1 %edx,%ebx 13:3d 01 f0 ff ff cmp1 $0xfffff001,%eax 18:0f 83 fc ff ff jae la 1d:ff 1a:R_386_PC32 _syscall_error 1e:c3 ret ? 進(jìn)入函數(shù) sethostname()以后,堆棧指針 %esp指向返回地址,而在堆棧指針加 4的地方則是調(diào)用該函數(shù)的第一個參數(shù) name,加 8是第二個參數(shù)len。第二條指令是將相對于寄存器 %esp位移為8的內(nèi)容存入寄存器 %ecx,即將參數(shù) len存入寄存器 %ecx,第三條指令就是把參數(shù) name存入寄存器 %ebx,第四條指令把代表 sethostname()的系統(tǒng)調(diào)用號 0x4a存入寄存器 %eax,接著就是中斷指令 int 0x80。 ? 從系統(tǒng)調(diào)用返回后,先從 %edx中恢復(fù)%ebx原先的內(nèi)容,即在系統(tǒng)調(diào)用之前保存在 %edx中的(第一條指令),而 %edx中的內(nèi)容就丟失了。這是一種約定, gcc在使用寄存器時會遵守這個約定。接著檢查放在 %eax中的系統(tǒng)調(diào)用的返回值。若 %eax的內(nèi)容在 0xfffff001和 0xffffffff之間,即 1到 4095之間,表示出錯了,要轉(zhuǎn)向_syscall_error()并從那里返回。 ? : file format elf32_i386 disassemble of : 00000000 _syscall_error): 0:f7 d8 negl %eax 00000002 _syscall_error_1: 2:50 push1 %eax 3:e8 fc ff ff ff call 4 _syscall_error_1+0x2 4:R_386_PC32 _errno_location 8:59 pop1 %ecx 9:89 08 mov1 %ecx,(%eax) b:b8 ff ff ff ff mov1 0xffffffff,%eax 10:c3 ret file of format elf32i386 disassembly of : 00000000 _errno_location: 0:55 push1 %ebp 1:89 e5 mov1 %esp,%ebp 3:b8 00 00 00 00 mov1 $0x0,%eax 4:R_386_32 errno 8:89 ec mov1 %ebp,%esp a:5d pop1 %ebp b:c3 ret 在 _syscall_error中 , 先將 %eax中的負(fù)值取絕對值 , 得到出錯代碼 , 并將其壓入堆棧。 接著,又調(diào)用 _erron_location(),將全局變?yōu)? errno中。最后,在返回之前,將 %eax的內(nèi)容變?yōu)?1。 這樣,通過寄存器 %ec
點(diǎn)擊復(fù)制文檔內(nèi)容
教學(xué)課件相關(guān)推薦
文庫吧 www.dybbs8.com
公安備案圖鄂ICP備17016276號-1