為什麼linux系統會提供模組?
隨著os的演化,功能越來越多,就會有乙個問題:linux本身是乙個單核心,它的效率高但是它的可擴充套件性和可維護性差,如果把所有的功能都放到os的核心中,那麼核心就會非常龐大並且笨拙,如果不放在核心中,那麼這些功能要麼不能執行,要麼執行非常緩慢。
所以聰明的工程師們就發明了模組,來解決這個問題。
但是核心模組也是有缺點的,首先,載入解除安裝需要時間,會降低系統效能;模組需要管理結構和額外的**,因此需要更多的記憶體;模組只能間接地訪問核心資源,所以效率較低;最重要的是模組一旦被載入,就成了核心的一部分,就有可能使核心崩潰,也有安全隱患;最後還會有版本問題。
在開始模組的插入之前,我們需要先了解一些基本的內容,就是我們和linux互動的方式,在使用者態我們都是直接printf列印出來就好了,但是在linux中,我們都是通過日誌資訊來了解系統狀況的,linux有專門的檔案系統來給使用者提供資訊(/proc,之後會有專門的文章來介紹),在這裡我們僅簡單介紹一下。
我們都知道,printf可以幫助我們在螢幕上列印出文字資訊,但是這僅僅是在linux的使用者態中使用的,不幸的是在核心中不能使用printf了。當linux執行起來以後,核心本身就會記錄一些資訊,並提供整個作業系統的狀態資訊,printk是最常見的linux核心向終端使用者傳遞訊息的方式。
printk和printf的區別就是printk可以指定訊息的列印級別,核心根據這個級別來決定是否將訊息列印到終端上:
核心使用printk()而不是printf()的原因是核心沒有鏈結標準c函式庫。但其實printk和printf函式的介面完全一樣,可以在控制台顯示1024個字元。
printk函式在執行的時候,首先設法獲取控制台訊號量,然後將要輸出的字元存入控制台的日誌緩衝區,再呼叫控制台驅動程式來重新整理緩衝區。如果控制台無法獲取控制台訊號量,就只能把要輸出的字元儲存到日誌緩衝區,並依賴擁有控制台訊號量的程序來重新整理這個緩衝區。注意在printk儲存任何資料到日誌緩衝區之前,必須使用日誌緩衝區鎖,這樣才能保證併發呼叫printk時不會相互影響。如果已經獲得了控制台訊號量,那麼重新整理日誌緩衝區之前,可以多次呼叫printk()函式,所以,printk不能來表明任何程式的執行時間。
首先,linux核心有多種方式可以用於儲存日誌和資訊。linux核心通過klogd()傳送訊息,並給它標上適當的警告級。所有級別的訊息都儲存在/proc/kmsg中。
dmesg是乙個命令列工具,可以用於顯示儲存在/proc/kmsg中的緩衝區內容,並能夠根據訊息級別來選擇是否要過濾這個緩衝區。
linux系統的/var/log/message下儲存的是大多數已經記錄的系統的資訊。對於某些儲存了已接收訊息的特定位置,可以借助syslogd程式來讀取/etc/syslogd.conf的內容。根據syslogd.conf中項的不同,日誌資訊可以儲存到許多不同的檔案中去,但是該檔案在不同版本的linux系統中有所不同,不過一般是在/var/log/meaasga下。
了解了以上內容之後,我們就可以來編寫核心模組了,和每種程式語言類似,核心模組的編寫也是有基本的框架的:c檔案+makefile檔案。
c檔案我們在自己的資料夾下新建c檔案,然後編寫**。
直接來看**,我將所有需要知道的東西都寫在注釋中了:
# include
//對應使用module_init/module_exit,所有模組都要使用,這個檔案必須被包含進來
# include
//包含常用的核心函式
# include
//包含了巨集_init和_exit,告訴編譯程式相關的函式和變數僅用於初始化,編譯程式將標有_init的所有**儲存到特殊的記憶體段中,初始化結束後就釋放這段記憶體
/* * 模組的初始化函式lkp_init():向核心註冊模組提供新功能
* __init是用於初始化的修飾符
* printk()函式的使用:由核心定義,它把要列印的東西輸出到終端或者日誌裡去,
* */
static
int __init lkp_init
(void)/*
*模組的退出和清理函式lkp_exit():登出由模組提供所有的功能
* */
static
void __exit lkp_exit
(void
)//模組初始化的入口點,對於內建模組,核心在引導時呼叫該入口點;對於可載入模組則在該模組插入核心時才呼叫。
module_init
(lkp_init)
;//對於可載入模組,核心在此處呼叫cleanup_module函式,而對於內建的模組,它沒有什麼用。
module_exit
(lkp_exit);/*
* 模組的許可證宣告gpl,提示可能沒有gnu公共許可證
* */
module_license
("gpl"
);
makefile檔案
注意,makefile檔案的m必須是大寫,而且得和你要編譯的c檔案放在同乙個目錄。
接下來是**:
obj-m:=first.o
#這一行的-c的作用是告訴make程式讀取makefile或者做其他事情之前,先要改變linux的源目錄。
make -c /usr/src/linux-2.6.7 subdirs=
$pwd modules
來看這段**,我們可以發現我們每次需要編譯檔案的時候,都需要確定一下我們自己的linux系統中核心的版本,首先,檢視核心的版本在終端中使用uname -r命令即可,但是我們並不需要這樣子寫,可以寫成如下形式,移植性很強,以後只需要複製這個文件修改目標檔案.o的名字即可使用:
#makefile檔案注意:假如前面的.c檔案起名為first.c,那麼這裡的makefile檔案中的.o檔案就要起名為first.o 只有root使用者才能載入和解除安裝模組
obj-m:=first.o #產生first模組的目標檔案
#目標檔案 檔案 要與模組名字相同
current_path:=
$(shell pwd
) #模組所在的當前路徑
linux_kernel:=
$(shell uname -r)
#linux核心**的當前版本
linux_kernel_path:=/usr/src/linux-headers-$(linux_kernel)
all:
make -c $(linux_kernel_path)
m=$(current_path)
modules #編譯模組
#[tab] 核心的路徑 當前目錄編譯完放哪 表明編譯的是核心模組
clean:
make -c $(linux_kernel_path)
m=$(current_path)
clean #清理模組
插入/檢查/刪除模組
在編寫好c檔案和makefile檔案之後,在終端中使用make命令,即可編譯。編譯後會生成乙個.ko檔案,這個就是模組。
在linux中,插入刪除模組要有超級使用者許可權,所以要在命令前加上sudo。插入模組:
sudo insmod first.ko
之後可以檢視模組是否正確插入了:
lsmod
之後使用dmesg命令檢視日誌資訊:
dmesg
刪除模組只用寫模組名字即可,不用寫副檔名
sudo rmmod first
Linux學習(3) Linux鏈結概念
linux 鏈結分兩種,一種被稱為硬鏈結 hard link 另一種被稱為符號鏈結 symbolic link 情況下,ln命令產生硬鏈結。硬連線 硬連線指通過索引節點來進行連線。在 linux 的檔案系統中,儲存在磁碟分割槽中的檔案不管是什麼型別都給它分配乙個編號,稱為索引節點號 inode in...
3 Linux 詳解檔案許可權
輸出的內容是什麼呢?第1個字母 代表檔案型別 第2,3,4個字母 分別代表擁有者的讀,寫,執行許可權 第5,6,7個字母 分別代表所屬使用者組的讀,寫,執行許可權 第8,9,10個字母 分別代表其他使用者的讀,寫,執行許可權 如果對應位置為 表示沒有該許可權 注意,linux裡面一切皆檔案 chgr...
3 Linux命令之萬用字元
當使用某些linux命令時,可能會使用到統配符,以下是一些萬用字元。萬用字元 匹配任何字元。匹配任何單個字元。characters 匹配任何在字符集characters中的字元。characters 匹配任何不在字符集characters中的字元。class 匹配作為指定類成員的任何字元。class...