Helloworld 驅動模組載入
介紹
本文引用《linux裝置驅動開發》書中部分解釋,記錄開篇第一章 helloworld
程式
以下內容需要掌握如下基礎資訊linux模組概念、連結編譯、c語言基礎
內容
helloworld.c
#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> static int __init hellowolrd_init(void) { pr_info("Hello world!\n"); return 0; } static void __exit hellowolrd_exit(void) { pr_info("End of the world\n"); } module_init(hellowolrd_init); module_exit(hellowolrd_exit); MODULE_AUTHOR("John Madieu <[email protected]>"); MODULE_LICENSE("GPL");
執行 make
命令之後,它會生成兩個模組
After running make
command, there will be two modules:
- helloworld.ko
- helloworld-params.ko
第一個模組是基本helloworld驅動程式,第二個也是相同的,但是它接收一些引數,並在核心除錯訊息中列印這些引數,載入第一個模組後,將在核心中新增兩個除錯訊息,
安裝模組
# insmod ./helloworld.ko
解除安裝模組
# rmmod -f helloworld
核心訊息
#dmesg [...] [38535.487568] Hello world! [38542.391099] End of the world
對於第二個模組,可以使用下面方式載入
# insmod ./helloworld-params.ko
如果未提供任何引數,將使用預設值:
$ dmesg [...] [37858.595126] Hello world with parameters! [37858.595129] The *mystr* parameter: hello [37858.595130] The *myint* parameter: 1 [37858.595131] The *myarr* parameter: 0, 1, 2 [37887.232643] End of the world
我們傳入一些引數之後,將打印出如下訊息
# insmod ./helloworld-params.ko mystr="packtpub" myint=255 myarr=23,4,7 # dmesg [...] [37892.417968] Hello world with parameters! [37892.417970] The *mystr* parameter: packtpub [37892.417971] The *myint* parameter: 255 [37892.417972] The *myarr* parameter: 23, 4, 7 [37895.222808] End of the world
模組的入點和出點
核心驅動程式都有入點和出點:前者對應於模組載入時呼叫的函式(modprobe和insmod,該內容在書中有介紹),後者是模組解除安裝時執行的函式(在執行rmmod和modprobe -r 時,該內容書中有介紹)。
main()函式使用C/C++編寫的每個使用者空間程式的入點,當這個函式返回時,程式將退出。而對於核心模組,情況就不一樣了:入點可以隨意命名,它也不像使用者空間程式那樣在main()返回是退出,其出點在另一個函式中定義,開發人員 要做的就是通知核心把 哪些函式作為入點或出點來執行。實際上,唯一必須要做的是把它們作為引數提供為 module_init()
和 module_exit()
巨集,將它們標識為相應的載入和刪除函式。
綜上所述, module_init()
用於宣告模組載入(使用insmod或modprobe)時應該呼叫的函式。初始化函式中要完成的操作是定義模組的行為。 module_exit()
用於宣告模組解除安裝(使用rmmod)時應該呼叫的函式。
程式碼中 __init
和 __exit
屬性
__init和__exit實際上是在include/linux/init.h中定義的核心巨集,如下所示:
#define __init__section(.init.text) #define __exir__section(.exit.text)
ELF目標檔案
編譯檔案工作方式,ELF目標檔案有不同的命名部分組成,其中一部分是必需的,它們稱為ELF標準的基礎,但也可以根據自己的需要構建任一部分,並由特殊程式使用,核心就是這樣做的。如上所屬的核心巨集的工作方式,如需要了解它的原理ELF目標檔案的可執行和可連結格式說明需要了解
可以通過下列命令打印出指定核心模組module.ko的不同組成部分
~/.../LinuxDeviceDriversDevelopment_Code/Chapter02 >>> objdump -h helloworld.ko helloworld.ko: 檔案格式 elf64-x86-64 節: Idx Name Size VMA LMA File off Algn 0 .text 00000000 0000000000000000 0000000000000000 00000040 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .init.text 00000015 0000000000000000 0000000000000000 00000040 2**0 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 2 .exit.text 0000000c 0000000000000000 0000000000000000 00000055 2**0 CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE 3 .rodata.str1.1 00000024 0000000000000000 0000000000000000 00000061 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 __mcount_loc 00000008 0000000000000000 0000000000000000 00000085 2**0 CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA 5 .rodata 0000008c 0000000000000000 0000000000000000 000000a0 2**5 CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA 6 .rodata.str1.8 00000058 0000000000000000 0000000000000000 00000130 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .modinfo 000000af 0000000000000000 0000000000000000 00000188 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 8 .orc_unwind 0000001e 0000000000000000 0000000000000000 00000237 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA 9 .orc_unwind_ip 00000014 0000000000000000 0000000000000000 00000255 2**0 CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA 10 .note.gnu.property 00000030 0000000000000000 0000000000000000 00000270 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 11 .note.gnu.build-id 00000024 0000000000000000 0000000000000000 000002a0 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 12 .note.Linux 00000030 0000000000000000 0000000000000000 000002c4 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 13 .data 00000000 0000000000000000 0000000000000000 000002f4 2**0 CONTENTS, ALLOC, LOAD, DATA 14 .printk_index 00000010 0000000000000000 0000000000000000 000002f8 2**3 CONTENTS, ALLOC, LOAD, RELOC, DATA 15 .gnu.linkonce.this_module 000003c0 0000000000000000 0000000000000000 00000340 2**6 CONTENTS, ALLOC, LOAD, RELOC, DATA, LINK_ONCE_DISCARD 16 .bss 00000000 0000000000000000 0000000000000000 00000700 2**0 ALLOC 17 .debug_info 000038ec 0000000000000000 0000000000000000 00000700 2**0 CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS 18 .debug_abbrev 00000609 0000000000000000 0000000000000000 00003fec 2**0 CONTENTS, READONLY, DEBUGGING, OCTETS 19 .debug_aranges 00000060 0000000000000000 0000000000000000 000045f5 2**0 CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS 20 .debug_ranges 00000030 0000000000000000 0000000000000000 00004655 2**0 CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS 21 .debug_line 000005a7 0000000000000000 0000000000000000 00004685 2**0 CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS 22 .debug_str 00003206 0000000000000000 0000000000000000 00004c2c 2**0 CONTENTS, READONLY, DEBUGGING, OCTETS 23 .comment 00000026 0000000000000000 0000000000000000 00007e32 2**0 CONTENTS, READONLY 24 .note.GNU-stack 00000000 0000000000000000 0000000000000000 00007e58 2**0 CONTENTS, READONLY 25 .debug_frame 00000048 0000000000000000 0000000000000000 00007e58 2**3 CONTENTS, RELOC, READONLY, DEBUGGING, OCTETS 26 .BTF 00000050 0000000000000000 0000000000000000 00007ea0 2**0 CONTENTS, READONLY
如上只有少部分屬於ELF標準
- .text: 包含程式程式碼,也稱為程式碼。
- .data: 包含初始化資料,也稱為資料段。
- .rodata: 用於只讀資料。
- .comment: 註釋。
- 未初始化化的資料段,也稱為有符號開始的塊(block started by symbol,bss)。
ELF連結器
對於程式碼程式中核心新增的其他部分,討論為時過早,我們首先要討論連結器是如何將目標程式檔案排列,並將相關 .init.text
連結到程式中 hellowolrd_init
及 .exit.text
連結到程式中 hellowolrd_exit
要解釋這一行為,首先我們要了解一個叫做連結器(Linux系統上的ld)程式,該程式負責將符號(資料、程式碼等)放置到生成的二進位制檔案中的適當部分,以便在程式執行時可以被載入器處理。二進位制檔案中的這些部分可以自定義、更改它們的預設位置,甚至可以通過提供連結器指令碼[稱為連結器定義檔案( LDF
)或連結器定義指令碼( LDS
)]來新增其他部分。要實現這些操作只需通過編譯器指令把符號的位置告知連結器即可, GUN C
編譯器為此提供了一些屬性。Linux核心提供了一個自定義 LDS
檔案,它位於 arch/<arch>/kernel/vmlinux.lds,.s
中。對於要放置在核心LDS檔案所對映的專用部分中的符號,使用 __init
和 __exit
進行標記。
總之, __init
和 __exit
是Linux指令(實際上是巨集),他們使用C編譯器屬性指定符號的位置。這些指令指示編譯器將以它們為字首的程式碼分別放在 .init.text
和 .exit.text
部分,雖然核心可以訪問不同的物件部分。
- 分享自己平時使用的socket多客戶端通訊的程式碼技術點和軟體使用
- iNeuOS工業網際網路作業系統,增加2154個檢視建模(WEB組態)行業向量圖元、大屏背景及相關圖元
- 多臺雲伺服器的 Kubernetes 叢集搭建
- Elasticsearch學習系列四(聚合搜尋)
- 關於swiper外掛在vue2的使用
- 使用 Abp.Zero 搭建第三方登入模組(一):原理篇
- LVGL庫入門教程 - 顏色和影象
- 物聯網?快來看 Arduino 上雲啦
- SpringBoot JWT Redis 開源知識社群系統
- CVPR2022 | 可精簡域適應
- Spring框架系列(3) - 深入淺出Spring核心之控制反轉(IOC)
- 面試突擊59:一個表中可以有多個自增列嗎?
- CVPR2022 | 弱監督多標籤分類中的損失問題
- JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文帶你釐清箇中曲直,給你個選擇SpringDataJPA的...
- Spring Security:使用者和Spring應用之間的安全屏障
- Mybatisi和Spring整合原始碼分析
- 前端學習 linux —— 第一篇
- call apply bind的作用及區別? 應用場景?
- Bika LIMS 開源LIMS集——實驗室檢驗流程概述及主頁、面板
- 軟體專案管理 7.5.專案進度模型(SPSP)