本章介紹系統(tǒng)編程的基礎(chǔ)概念和一些后續(xù)章節(jié)用到的函數(shù)及頭文件,并說明了可移植性問題。
系統(tǒng)調(diào)用是受控的內(nèi)核入口,通過系統(tǒng)調(diào)用,進(jìn)程可以請求內(nèi)核以自己的名義去執(zhí)行某些動作,比如創(chuàng)建子進(jìn)程,執(zhí)行I/O操作,進(jìn)行進(jìn)程間的通信等。
系統(tǒng)調(diào)用與C語言的函數(shù)調(diào)用類似。但是系統(tǒng)調(diào)用的過程比C語言函數(shù)調(diào)用復(fù)雜,開銷也大得多。
Linux 的系統(tǒng)調(diào)用通過 int 0x80 實(shí)現(xiàn),用系統(tǒng)調(diào)用號來區(qū)分入口函數(shù)。操作系統(tǒng)實(shí)現(xiàn)系統(tǒng)調(diào)用的基本過程是:
應(yīng)用程序調(diào)用庫函數(shù)(API);
API 將系統(tǒng)調(diào)用號存入 EAX,然后通過中斷調(diào)用使系統(tǒng)進(jìn)入內(nèi)核態(tài);
內(nèi)核中的中斷處理函數(shù)根據(jù)系統(tǒng)調(diào)用號,調(diào)用對應(yīng)的內(nèi)核函數(shù)(系統(tǒng)調(diào)用);
系統(tǒng)調(diào)用完成相應(yīng)功能,將返回值存入 EAX,返回到中斷處理函數(shù);
中斷處理函數(shù)返回到 API 中;
API 將 EAX 返回給應(yīng)用程序。
本章后續(xù)部分重點(diǎn)介紹了后面章節(jié)所要使用的頭文件及其實(shí)現(xiàn),主要如下:
ename.c.inc
error_functions.h
get_num.h
tlpi_hdr.h
其中ename.c.inc文件定義了一個字符串?dāng)?shù)組,用于對應(yīng)錯誤碼的名稱。
error_functions.h文件聲明了本書自定義的錯誤處理函數(shù)。
get_num.h文件聲明了本書自定義的數(shù)值提取函數(shù)。
tlpi_hdr.h文件則包含了后續(xù)需用到的系統(tǒng)調(diào)用頭文件。
由于存在3個頭文件以及2個實(shí)現(xiàn),每次編譯時必須對實(shí)現(xiàn)也進(jìn)行編譯,為方便后續(xù)學(xué)習(xí),采用將頭文件復(fù)制到默認(rèn)的編譯器尋找目錄下,并將實(shí)現(xiàn)打包成靜態(tài)庫,然后使用別名來默認(rèn)鏈接靜態(tài)庫。
以Debian/Ubuntu為例,具體操作如下:
第一步:下載本書所給的源碼文件
wget "http://man7.org/tlpi/code/download/tlpi-161214-dist.tar.gz"
或者點(diǎn)此下載
第二步:解壓后,make編譯
tar -zxvf tlpi-161214-dist.tar.gz
cd tlpi-dist/
make -j
第三步:拷貝頭文件至系統(tǒng)目錄
cd lib/
sudo cp tlpi_hdr.h /usr/local/include/
sudo cp get_num.h /usr/local/include/
sudo cp error_functions.h /usr/local/include/
sudo cp ename.c.inc /usr/local/include/
第四步:制作靜態(tài)庫文件
g++ -c get_num.c error_functions.c
ar -crv libtlpi.a get_num.o error_functions.o
sudo cp libtlpi.a /usr/local/lib
第五步:簡化編譯命令
alias gl++='new() { g++ $1 -ltlpi;}; new'
第五步需要在當(dāng)前用戶的主目錄下的.bashrc文件中設(shè)置別名,由于alias不支持參數(shù),因此需要使用函數(shù)來間接實(shí)現(xiàn),并且接受一個參數(shù)$1以指定對某個源文件進(jìn)行編譯并鏈接之前的靜態(tài)庫libtlpi.a。配置完畢后重新讀入.bashrc文件以生效。這里使用函數(shù)來接受一個參數(shù)存在一個缺點(diǎn)即只能使用一個命令行參數(shù),多余參數(shù)將被忽略。
完成上面的步驟后,即可使用快捷命令來編譯我們的程序了:
gl++ main.cpp
該命令將編譯生成a.out文件。
如果不想使用第五步來簡化,則每次編譯手動來鏈接庫,命令如下:
g++ main.cpp -o main -ltlpi