日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

程序员的自我修养--链接、装载与库笔记:系统调用与API

發(fā)布時(shí)間:2023/11/27 生活经验 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 程序员的自我修养--链接、装载与库笔记:系统调用与API 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

系統(tǒng)調(diào)用(System Call)是應(yīng)用程序(運(yùn)行庫也是應(yīng)用程序的一部分)與操作系統(tǒng)內(nèi)核之間的接口,它決定了應(yīng)用程序是如何與內(nèi)核打交道的。無論程序是直接進(jìn)行系統(tǒng)調(diào)用,還是通過運(yùn)行庫,最終還是會到達(dá)系統(tǒng)調(diào)用這個(gè)層面上。

1. 系統(tǒng)調(diào)用介紹

什么是系統(tǒng)調(diào)用:在現(xiàn)代的操作系統(tǒng)里,程序運(yùn)行的時(shí)候,本身是沒有權(quán)利訪問多少系統(tǒng)資源的。由于系統(tǒng)有限的資源有可能被多個(gè)不同的應(yīng)用程序同時(shí)訪問,因此,如果不加以保護(hù),那么各個(gè)應(yīng)用程序難免產(chǎn)生沖突。所以現(xiàn)代操作系統(tǒng)都將可能產(chǎn)生沖突的系統(tǒng)資源給保護(hù)起來,阻止應(yīng)用程序直接訪問。這些系統(tǒng)資源包括文件、網(wǎng)絡(luò)、IO、各種設(shè)備等。舉個(gè)例子,無論在Windows下還是Linux下,程序員都沒有機(jī)會擅自去訪問硬盤的某扇區(qū)上面的數(shù)據(jù),而必須通過文件系統(tǒng);也不能擅自修改任意文件,所有的這些操作都必須經(jīng)由操作系統(tǒng)所規(guī)定的方式來進(jìn)行,比如我們使用fopen去打開一個(gè)沒有權(quán)限的文件就會發(fā)生失敗。此外,有一些行為,應(yīng)用程序不借助操作系統(tǒng)是無法辦到或不能有效地辦到的。為了讓應(yīng)用程序有能力訪問系統(tǒng)資源,也為了讓程序借助操作系統(tǒng)做一些必須由操作系統(tǒng)支持的行為,每個(gè)操作系統(tǒng)都會提供一套接口,以供應(yīng)用程序使用。這些接口往往通過中斷來實(shí)現(xiàn),比如Linux使用0x80號中斷作為系統(tǒng)調(diào)用的入口,Windows采用0x2E號中斷作為系統(tǒng)調(diào)用入口。

系統(tǒng)調(diào)用覆蓋的功能很廣,有程序運(yùn)行所必需的支持,例如創(chuàng)建/退出進(jìn)程和線程、進(jìn)程內(nèi)存管理,也有對系統(tǒng)資源的訪問,例如文件、網(wǎng)絡(luò)、進(jìn)程間通信、硬件設(shè)備的訪問,也可能有對圖形界面的操作支持,例如Windows下的GUI機(jī)制。

系統(tǒng)調(diào)用既然作為一個(gè)接口,而且是非常重要的接口,它的定義將十分重要。因?yàn)樗械膽?yīng)用程序都依賴于系統(tǒng)調(diào)用,那么,首先系統(tǒng)調(diào)用必須有明確的定義,即每個(gè)調(diào)用的含義、參數(shù)、行為都需要有嚴(yán)格而清晰的定義,這樣應(yīng)用程序(運(yùn)行庫)才可以正確地使用它;其次它必須保持穩(wěn)定和向后兼容,如果某次系統(tǒng)更新導(dǎo)致系統(tǒng)調(diào)用接口發(fā)生改變,新的系統(tǒng)調(diào)用接口與之前版本完全不同,這是無法想象的,因?yàn)樗兄澳苷_\(yùn)行的程序都將無法使用。所以操作系統(tǒng)的系統(tǒng)調(diào)用往往從一開始定義后就基本不做改變,而僅僅是增加新的調(diào)用接口,以保持向后兼容。

Linux系統(tǒng)調(diào)用:在x86下,系統(tǒng)調(diào)用由0x80中斷完成,各個(gè)通用寄存器用于傳遞參數(shù),EAX寄存器用于表示系統(tǒng)調(diào)用的接口號,每個(gè)系統(tǒng)調(diào)用都對應(yīng)于內(nèi)核源代碼中的一個(gè)函數(shù),它們都是以”sys_”開頭的,比如exit調(diào)用對應(yīng)內(nèi)核中的sys_exit函數(shù)。Linux內(nèi)核版本提供了很多個(gè)系統(tǒng)調(diào)用,這些系統(tǒng)調(diào)用都可以在程序里面直接使用,它的C語言形式被定義在/usr/include/unistd.h中,比如我們完全可以繞過glibc的fopen、fread、fclose打開讀取和關(guān)閉文件,而直接使用open()、read()和close()來實(shí)現(xiàn)文件的讀取,使用write向屏幕輸出字符串(標(biāo)準(zhǔn)輸出的文件句柄為0),使用read系統(tǒng)調(diào)用來實(shí)現(xiàn)讀取用戶輸入(標(biāo)準(zhǔn)輸入的文件句柄為1)。不過由于繞過了glibc的文件讀取機(jī)制,所以所有位于glibc中的緩沖、按行讀取文本文件等這些機(jī)制都沒有了,讀取的就是文件的原始數(shù)據(jù)。我們也可以使用Linux的man命令查看每個(gè)系統(tǒng)調(diào)用的詳細(xì)說明,如: man 2 read。

系統(tǒng)調(diào)用的弊端:系統(tǒng)調(diào)用完成了應(yīng)用程序和內(nèi)核交流的工作,事實(shí)上,包括Linux,大部分操作系統(tǒng)的系統(tǒng)調(diào)用都有兩個(gè)特點(diǎn):(1). 使用不便:操作系統(tǒng)提供的系統(tǒng)調(diào)用接口往往過于原始,程序員需要了解很多與操作系統(tǒng)相關(guān)的細(xì)節(jié)。如果沒有進(jìn)行很好的包裝,使用起來不方便。(2). 各個(gè)操作系統(tǒng)之間系統(tǒng)調(diào)用不兼容:首先Windows系統(tǒng)和Linux系統(tǒng)之間的系統(tǒng)調(diào)用就基本上完全不同,雖然它們的內(nèi)容很多都一樣,但是定義和實(shí)現(xiàn)大不一樣。即使是同系列的操作系統(tǒng)的系統(tǒng)調(diào)用都不一樣,比如Linux和UNIX就不相同。

“解決計(jì)算機(jī)的問題可以通過增加層來實(shí)現(xiàn)”,于是運(yùn)行庫挺身而出,它作為系統(tǒng)調(diào)用與程序之間的一個(gè)抽象層可以保持著這樣的特點(diǎn):(1). 使用簡便:因?yàn)檫\(yùn)行庫本身就是語言級別的,它一般都設(shè)計(jì)相對比較友好。(2). 形式統(tǒng)一:運(yùn)行庫有它的標(biāo)準(zhǔn),叫做標(biāo)準(zhǔn)庫,凡是所有遵循這個(gè)標(biāo)準(zhǔn)的運(yùn)行庫理論上都是相互兼容的,不會隨著操作系統(tǒng)或編譯器的變化而變化。

運(yùn)行時(shí)庫將不同的操作系統(tǒng)的系統(tǒng)調(diào)用包裝為統(tǒng)一固定的接口,使得同樣的代碼,在不同的操作系統(tǒng)下都可以直接編譯,并產(chǎn)生一致的效果。這就是源代碼級上的可移植性。但是運(yùn)行庫也有運(yùn)行庫的缺陷,比如C語言的運(yùn)行庫為了保證多個(gè)平臺之間能夠相互通用,于是它只能取各個(gè)平臺之間功能的交集。

2. 系統(tǒng)調(diào)用原理

特權(quán)級與中斷:現(xiàn)代的CPU常常可以在多種截然不同的特權(quán)級別下執(zhí)行指令,在現(xiàn)代操作系統(tǒng)中,通常也據(jù)此有兩種特權(quán)級別,分別為用戶模式(User Mode)和內(nèi)核模式(Kernel Mode),也被稱為用戶態(tài)和內(nèi)核態(tài)。由于有多種特權(quán)模式的存在,操作系統(tǒng)就可以讓不同的代碼運(yùn)行在不同的模式上,以限制它們的權(quán)力,提供穩(wěn)定性和安全性。系統(tǒng)調(diào)用是運(yùn)行在內(nèi)核態(tài)的,而應(yīng)用程序基本都是運(yùn)行在用戶態(tài)的。用戶態(tài)的程序如何運(yùn)行內(nèi)核態(tài)的代碼呢?操作系統(tǒng)一般是通過中斷(Interrupt)來從用戶態(tài)切換到內(nèi)核態(tài)。什么是中斷呢?中斷是一個(gè)硬件或軟件發(fā)出的請求,要求CPU暫停當(dāng)前的工作轉(zhuǎn)手去處理更加重要的事情

中斷一般具有兩個(gè)屬性,一個(gè)稱為中斷號(從0開始),一個(gè)稱為中斷處理程序(Interrupt Service Routine, ISR)。不同的中斷具有不同的中斷號而同時(shí)一個(gè)中斷處理程序一一對應(yīng)一個(gè)中斷號。在內(nèi)核中,有一個(gè)數(shù)組稱為中斷向量表(Interrupt Vector Table),這個(gè)數(shù)組的第n項(xiàng)包含了指向第n號中斷的中斷處理程序的指針。當(dāng)中斷到來時(shí),CPU會暫停當(dāng)前執(zhí)行的代碼,根據(jù)中斷的中斷號,在中斷向量表中找到對應(yīng)的中斷處理程序,并調(diào)用它。中斷處理程序執(zhí)行完成之后,CPU會繼續(xù)執(zhí)行之前的代碼。

通常意義上,中斷有兩種類型,一種稱為硬件中斷,這種中斷來自于硬件的異常或其它事件的發(fā)生,如電源掉電、磁盤被按下等。另一種稱為軟件中斷,軟件中斷通常是一條指令(i386下是int),帶有一個(gè)參數(shù)記錄中斷號,使用這條指定用戶可以手動觸發(fā)某個(gè)中斷并執(zhí)行其中斷處理程序。由于中斷號是很有限的,操作系統(tǒng)不會舍得用一個(gè)中斷號來對應(yīng)一個(gè)系統(tǒng)調(diào)用,而更傾向于用一個(gè)或少數(shù)幾個(gè)中斷號來對應(yīng)所有的系統(tǒng)調(diào)用。

基于int的Linux的經(jīng)典系統(tǒng)調(diào)用實(shí)現(xiàn):

(1). 觸發(fā)中斷:首先當(dāng)程序在代碼里調(diào)用一個(gè)系統(tǒng)調(diào)用時(shí),是以一個(gè)函數(shù)的形式調(diào)用的。

(2). 切換堆棧:在實(shí)際執(zhí)行中斷向量表的第0x80號元素所對應(yīng)的函數(shù)之前,CPU首先還要進(jìn)行棧的切換。在Linux中,用戶態(tài)和內(nèi)核態(tài)使用的是不同的棧,兩者各自負(fù)責(zé)各自的函數(shù)調(diào)用,互不干擾。但在應(yīng)用程序調(diào)用0x80號中斷時(shí),程序的執(zhí)行流程從用戶態(tài)切換到內(nèi)核態(tài),這時(shí)程序的當(dāng)前棧必須也相應(yīng)地從用戶棧切換到內(nèi)核棧。從中斷處理函數(shù)中返回時(shí),程序的當(dāng)前棧還要從內(nèi)核棧切換回用戶棧。

(3). 中斷處理程序:在int指令合理地切換了棧之后,程序的流程就切換到了中斷向量表中記錄的0x80號中斷處理程序。內(nèi)核里的系統(tǒng)調(diào)用函數(shù)往往以sys_加上系統(tǒng)調(diào)用函數(shù)名來命名,例如sys_fork、sys_open等。

Linux的新型系統(tǒng)調(diào)用機(jī)制:使用ldd來獲取一個(gè)可執(zhí)行文件ls的共享庫的依賴情況,如下表所示,可以看到linux-vdso.so.1沒有與任何實(shí)際的文件相對應(yīng),這個(gè)共享庫是Linux用于支持新型系統(tǒng)調(diào)用的”虛擬”共享庫。linux-vdso.so.1并不存在實(shí)際的文件,它只是操作系統(tǒng)生成的一個(gè)虛擬動態(tài)共享庫(Virtual Dynamic Shared Library, VDSO)。可以通過Linux的proc文件系統(tǒng)來查看一個(gè)可執(zhí)行程序的內(nèi)存映像。命令cat ?/proc/self/maps可以查看cat命令自己的內(nèi)存布局。我們可以看見地址0x7ffdc0d43000到0x7ffdc0d45000的地方被映射了vdso,也就是linux-vdso.so.1。

3. Windows API

API的全稱為Application Programming Interface,即應(yīng)用程序編程接口。Windows API是指Windows操作系統(tǒng)提供給應(yīng)用程序開發(fā)者的最底層的、最直接與Windows打交道的接口。在Windows操作系統(tǒng)下,CRT是建立在Windows API之上的。另外還有很多對Windows API的各種包裝庫,MFC就是很著名的一種以C++形式封裝的庫。很多操作系統(tǒng)是以系統(tǒng)調(diào)用作為應(yīng)用程序最底層的,而Windows的最底層接口是Windows API。Windows API是Windows編程的基礎(chǔ),盡管Windows的內(nèi)核提供了數(shù)百個(gè)系統(tǒng)調(diào)用(Windows又把系統(tǒng)調(diào)用稱作系統(tǒng)服務(wù)(System Service)),但是出于種種原因,微軟并沒有將這些系統(tǒng)調(diào)用公開,而在這些系統(tǒng)調(diào)用之上,建立了這樣一個(gè)API層,讓程序員只能調(diào)用API層的函數(shù),而不是如Linux一般直接使用系統(tǒng)調(diào)用。

Windows API概覽:Windows API是以DLL導(dǎo)出函數(shù)的形式暴露給應(yīng)用程序開發(fā)者的。它被包含在諸多的系統(tǒng)DLL內(nèi),規(guī)模上非常龐大。微軟把這些Windows API DLL導(dǎo)出函數(shù)的聲明的頭文件、導(dǎo)出庫、相關(guān)文件和工具一起提供給開發(fā)者,并讓它們成為Software Development Kit(SDK)。SDK可以單獨(dú)地在微軟的官方網(wǎng)站下載,也可以被集成到Visual Studio這樣的開發(fā)工具中。當(dāng)我們安裝了Visual Studio后,可以在SDK的安裝目錄下找到所有的Windows API函數(shù)聲明。其中有一個(gè)頭文件”Windows.h”包含了Windows API的核心部分,只要我們在程序里面包含了它,就可以使用Windows API的核心部分了。

Windows API隨著Windows版本的升級也經(jīng)歷了好幾個(gè)版本,每次Windows進(jìn)行大升級的時(shí)候,也會引入新版本的API。Windows API現(xiàn)在的數(shù)量已經(jīng)十分龐大,它們按照功能被劃分成了幾大類別,如下圖所示:

由于Windows API所提供的接口還是相對比較原始的,所以直接使用API進(jìn)行程序開發(fā)往往效率較低。Windows系統(tǒng)在API之上建立了很多應(yīng)用模塊,這些應(yīng)用模塊是對Windows API的功能的擴(kuò)展。

為什么要使用Windows API:系統(tǒng)調(diào)用實(shí)際上是非常依賴于硬件結(jié)構(gòu)的一種接口,它受到硬件的嚴(yán)格控制,比如寄存器的數(shù)量、調(diào)用時(shí)的參數(shù)傳遞、中斷號、堆棧切換等,都與硬件密切相關(guān)。如果硬件結(jié)構(gòu)稍微發(fā)生改變,大量的應(yīng)用程序可能就會出現(xiàn)問題(特別是那些與CRT靜態(tài)鏈接在一起的)。為了盡量隔離硬件結(jié)構(gòu)的不同而導(dǎo)致的程序兼容性問題,Windows系統(tǒng)把系統(tǒng)調(diào)用包裝了起來,使用DLL導(dǎo)出函數(shù)作為應(yīng)用程序的唯一可用的接口暴露給用戶。除了隔離硬件結(jié)構(gòu)不同之外,Windows本身也有可能使用不同版本的內(nèi)核,所以系統(tǒng)調(diào)用的接口自然也是不一樣的。

GitHub:https://github.com/fengbingchun/Messy_Test

總結(jié)

以上是生活随笔為你收集整理的程序员的自我修养--链接、装载与库笔记:系统调用与API的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。