初探linux內核編程,參數傳遞以及模塊間函數調用

来源:http://www.cnblogs.com/yuuyuu/archive/2016/01/11/5119891.html
-Advertisement-
Play Games

一.前言 我們一起從3個小例子來體驗一下linux內核編程。如下:1.內核編程之hello world2.模塊參數傳遞3.模塊間函數調用二.準備工作 首先,在你的linux系統上面安裝linux頭文件,debian系列:1 $:sudo apt-...


一.前言                                 

我們一起從3個小例子來體驗一下linux內核編程。如下:

1.內核編程之hello world

2.模塊參數傳遞

3.模塊間函數調用

二.準備工作                          

首先,在你的linux系統上面安裝linux頭文件,debian系列:

1 $:sudo apt-get install linux-headers-`uname -r`

安裝後,在你的/lib/modules/目錄下有你剛剛安裝的頭文件版本號對應的目錄。頭文件夾下麵還有個build文件夾,裡面的Makefile文件是等會要編譯內核模塊用的。如圖,這是我機器上面的:

註意:安裝的頭文件版本一定要和你的系統版本一樣,不然你自己編寫的模塊不能插入到本機的內核。如果你apt-get安裝頭文件時,沒有對應的頭文件,或者你的源裡面放不穩定版本的源後,依然沒有對應的頭文件,你可以到這裡搜索需要的deb包來安裝。再或者下載跟本機對應的內核源碼來構建環境。

三.內核編程之hello world    

我們先來瞭解下內核模塊文件的入口和出口。它由2個巨集來註冊入口和出口,分別是:

1 module_init(x);
2 module_exit(x);

這2個巨集在頭文件目錄的include/linux/module.h。巨集裡面的x代表註冊到內核的入口和出口函數。通俗一點講就是模塊初始化和模塊卸載時調用的函數。

初始化函數的形式:int my_init(void);

退出函數的形式:void my_exit(void);

另外還有一些巨集:

MODULE_LICENSE(_license):模塊的許可證。

MODULE_AUTHOR(_author):模塊的作者。

MODULE_VERSION(_version):模塊版本

MODULE_DESCRIPTION(_description):模塊的描述。

還有一些就不一一舉例了。

現在,我來看最簡單的hello world例子:

文件名:kernel_hello.c

 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 
 5 /* 以下4個巨集分別是許可證,作者,模塊描述,模塊版本 */
 6 MODULE_LICENSE("Dual BSD/GPL");
 7 MODULE_AUTHOR("yuuyuu");
 8 MODULE_DESCRIPTION("kernel module hello");
 9 MODULE_VERSION("1.0");
10 
11 /* 入口函數 */
12 static int hello_init(void)
13 {
14     printk(KERN_ALERT "hello_init() start\n");
15 
16     return 0;
17 }
18 
19 /* 退出函數 */
20 static void hello_exit(void)
21 {
22     printk(KERN_ALERT "hello_exit() start\n");
23 }
24 
25 /* 註冊到內核 */
26 module_init(hello_init);
27 module_exit(hello_exit);

上面的printk()函數時內核自己實現的輸出函數,KERN_ALERT時輸出信息的級別!

然後再寫一個很簡單的Makefile文件:

1 KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
2 PWD := $(shell pwd)
3 
4 obj-m := kernel_hello.o
5 
6 default:
7     $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules

KERNAL_DIR:你剛剛安裝頭文件的目錄

PWD:代表當前你編寫模塊文件的目錄。

obj-m:模塊的依賴目標文件。另外,內核的Makefile文件:obj-m代表將目標文件編譯成模塊,obj-y代表編譯到內核,ojb-n代表不編譯。

-C:執行make的時候,把工作目錄切換到-C後面指定的參數目錄,這裡即頭文件目錄下的build目錄。

M:這個M時內核Makefile裡面的一個變數。作用時回到當前目錄繼續讀取Makefile,這裡的就是讀完build目錄下的Makefile之後再回到我們的這個目錄,讀取我們剛剛編寫的那個Makefile。

最後的modules是代表編譯模塊。

現在我們來編譯下,在我們編寫Makefile的目錄下執行make,會看到生成了模塊文件kernel_hello.ko

 

查看模塊信息:sudo modinfo kernel_hello.ko

可以看到剛剛那幾個巨集插入的模塊信息。

 現在我們一口氣執行4個動作:插入模塊,查看內核已插入的模塊,卸載模塊,查看dmesg信息:

可以看到,模塊在初始化和退出時都列印了函數裡面的信息。

 

四.模塊參數傳遞                    

模塊的參數傳遞也是一個巨集,在頭文件目錄的include/linux/moduleparam.h

1 module_param(name, type, perm)

name:模塊中的變數名,也是用戶可指定參數名。

type:byte,short,ushot,int,uint,long,ulong,charp,bool這些

perm:模塊的許可權控制。跟linux文件許可權控制一樣的。

文件名:kernel_hello_param.c

 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 
 5 /* 以下4個巨集分別是許可證,作者,模塊描述,模塊版本 */
 6 MODULE_LICENSE("Dual BSD/GPL");
 7 MODULE_AUTHOR("yuuyuu");
 8 MODULE_DESCRIPTION("kernel module hello");
 9 MODULE_VERSION("1.0");
10 
11 static char *msg;
12 module_param(msg, charp, 0644);
13 
14 /* 入口函數 */
15 static int hello_init(void)
16 {
17     printk(KERN_ALERT "hello_init() start\n");
18     printk(KERN_ALERT "%s\n", msg);
19 
20     return 0;
21 }
22 
23 /* 退出函數 */
24 static void hello_exit(void)
25 {
26     printk(KERN_ALERT "hello_exit() start\n");
27 }
28 
29 /* 註冊到內核 */
30 module_init(hello_init);
31 module_exit(hello_exit);

比上一個文件,就增加了11,12,18行。註意第12行的charp,是內核的字元指針。

編譯後,傳參插入,dmesg查看信息:

插入的參數msg跟在模塊後面即可

 

五.模塊間函數調用                

模塊的函數導出到符號表才可以供其他函數使用,需要用到巨集:

1 EXPORT_SYMBOL(sym)

該巨集在include/linux/export.h裡面。

既然模塊間函數調用,我們要編寫2個模塊。

文件一:kernel_fun.h

1 #ifndef KERNEL_FUN_H
2 #define KERNEL_FUN_H
3 
4 void fun(void);
5 
6 #endif

文件二,要導出的模塊文件:kernel_fun.c

 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/export.h>
 5 
 6 #include "kernel_fun.h"
 7 
 8 /* 以下4個巨集分別是許可證,作者,模塊描述,模塊版本 */
 9 MODULE_LICENSE("Dual BSD/GPL");
10 MODULE_AUTHOR("yuuyuu");
11 MODULE_DESCRIPTION("kernel module hello");
12 MODULE_VERSION("1.0");
13 
14 /* 入口函數 */
15 static int fun_init(void)
16 {
17     printk(KERN_ALERT "fun_init() start\n");
18 
19     return 0;
20 }
21 
22 void fun()
23 {
24     printk(KERN_ALERT "fun() is called\n");
25 }
26 
27 /* 退出函數 */
28 static void fun_exit(void)
29 {
30     printk(KERN_ALERT "fun_exit() start\n");
31 }
32 
33 /* 註冊到內核 */
34 module_init(fun_init);
35 module_exit(fun_exit);
36 
37 /* 導出符號表 */
38 EXPORT_SYMBOL(fun);

最後一行就是導出到符號表。

 

文件三,要調用模塊文件二的函數:kernel_mod.c

 1 #include <linux/init.h>
 2 #include <linux/module.h>
 3 #include <linux/kernel.h>
 4 #include <linux/export.h>
 5 
 6 #include "kernel_fun.h"
 7 
 8 /* 以下4個巨集分別是許可證,作者,模塊描述,模塊版本 */
 9 MODULE_LICENSE("Dual BSD/GPL");
10 MODULE_AUTHOR("yuuyuu");
11 MODULE_DESCRIPTION("kernel module hello");
12 MODULE_VERSION("1.0");
13 
14 /* 入口函數 */
15 static int mod_init(void)
16 {
17     printk(KERN_ALERT "mod_init() start\n");
18 
19     /* 調用fun */
20     fun();
21     return 0;
22 }
23 
24 /* 退出函數 */
25 static void mod_exit(void)
26 {
27     printk(KERN_ALERT "mod_exit() start\n");
28 }
29 
30 /* 註冊到內核 */
31 module_init(mod_init);
32 module_exit(mod_exit);

第20行即是調用其他模塊的函數

 

這裡要編譯2個模塊,對應的Makefile文件:

1 KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build
2 PWD := $(shell pwd)
3 
4 obj-m := kernel_mod.o kernel_fun.o
5 
6 default:
7     $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules

 

編譯好這2個模塊後,我們現在來驗證。註意,因為kernel_mod依賴kernel_fun,所以我要先插入kernel_fun模塊。

卸載模塊的時候,我們要先卸載kernel_mod,原因同上。

依次插入kernel_fun,查看它的符號表,然後插入kernel_mod,查看dmesg:

可以看到kernel_fun的fun()被kernle_mod調用了

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一轉眼又一年過去了,兩年沒回家了,下周回家看看!公司的項目已經開始內測了,再堅持三個月應該就能熬出頭了吧?然後自己的引擎和游戲就繼續開發,今年一定要出東西了!前些天狗被我喂上火了,眼裡流黃屎,嚇壞我了,趕緊黃瓜白菜一起才給輓救回來!之後就像遭報應一樣我病了,咽炎,感冒不止,現在還沒好,打了六針了!這...
  • 題目:Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.For example:Given the below binary tree and s...
  • 1、安裝好maven,在cmd中運行mvn –v,報錯:“maven Could not create the Java Virtual Machine” 2、分析:這是跟jvm有關,在cmd中運行 java –version,發現正常 3、繼續分析:在安裝maven的時候做了環境變數的配置: M2...
  • 題目:Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum...
  • 題目:Given a binary tree, find its minimum depth.The minimum depth is the number of nodes along the shortest path from the root node down to the nearest...
  • 本章內容在第三章《Java框架整合--企業中的項目架構以及多環境分配》的代碼上做修改,鏈接如下:http://www.cnblogs.com/java-zhao/p/5115136.html1、實現方式將之前ssmm0-userManagement中類路徑(src/main/resources)下的...
  • 題目:Given an array where elements are sorted in ascending order, convert it to a height balanced BST.思路:總是取中間點為rootpackage bst;public class ConvertSort...
  • 題目:Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root). F...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...