我們在編寫一個模塊的時候,常常使用一些宏定義來標識模塊的作者,版本,以及相關信息的描述,如:MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_LICENSE、MODULE_ALIAS等,那么這些宏是如何進行管理的呢?
小處誠實非小事!
今天帶著大家,我們來深入分析一下這些宏定義,其內(nèi)部的奧秘!
?
在上面提到的MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_LICENSE、MODULE_ALIAS,這些宏定義,查看其聲明,我們發(fā)現(xiàn):
/*?For?userspace:?you?can?also?call?me...?*/
#define?MODULE_ALIAS(_alias)?MODULE_INFO(alias,?_alias)
/*?Soft?module?dependencies.?See?man?modprobe.d?for?details.
?*?Example:?MODULE_SOFTDEP("pre:?module-foo?module-bar?post:?module-baz")
?
?/*
?*?The?following?license?idents?are?currently?accepted?as?indicating?free
?*?software?modules
?*
?*?"GPL"????[GNU?Public?License?v2?or?later]
?*?"GPL?v2"???[GNU?Public?License?v2]
?*?"GPL?and?additional?rights"?[GNU?Public?License?v2?rights?and?more]
?*?"Dual?BSD/GPL"???[GNU?Public?License?v2
?*??????or?BSD?license?choice]
?*?"Dual?MIT/GPL"???[GNU?Public?License?v2
?*??????or?MIT?license?choice]
?*?"Dual?MPL/GPL"???[GNU?Public?License?v2
?*??????or?Mozilla?license?choice]
?*
?*?The?following?other?idents?are?available
?*
?*?"Proprietary"???[Non?free?products]
?*
?*?There?are?dual?licensed?components,?but?when?running?with?Linux?it?is?the
?*?GPL?that?is?relevant?so?this?is?a?non?issue.?Similarly?LGPL?linked?with?GPL
?*?is?a?GPL?combined?work.
?*
?*?This?exists?for?several?reasons
?*?1.?So?modinfo?can?show?license?info?for?users?wanting?to?vet?their?setup
?*?is?free
?*?2.?So?the?community?can?ignore?bug?reports?including?proprietary?modules
?*?3.?So?vendors?can?do?likewise?based?on?their?own?policies
?*/
#define?MODULE_LICENSE(_license)?MODULE_INFO(license,?_license)
/*
?*?Author(s),?use?"Name?"?or?just?"Name",?for?multiple
?*?authors?use?multiple?MODULE_AUTHOR()?statements/lines.
?*/
#define?MODULE_AUTHOR(_author)?MODULE_INFO(author,?_author)
/*?What?your?module?does.?*/
#define?MODULE_DESCRIPTION(_description)?MODULE_INFO(description,?_description)
無論是MODULE_LICENSE、MODULE_AUTHOR、還是MODULE_DESCRIPTION,其最終都調(diào)用了MODULE_INFO的宏定義,并將對應的字符串參數(shù)傳入進去。
那么關鍵就在于MODULE_INFO這個宏定義了!
?
查看MODULE_INFO的定義,寫成了我們看不懂的形式,下面我們來逐步分析
//?include/linux/module.h
/*?Generic?info?of?form?tag?=?"info"?*/
#define?MODULE_INFO(tag,?info)?__MODULE_INFO(tag,?tag,?info)
//?include/linux/moduleparam.h
#define?__MODULE_INFO(tag,?name,?info)???????\
static?const?char?__UNIQUE_ID(name)[]???????\
??__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))???\
??=?__stringify(tag)?"="?info
//?include/linux/compiler-gcc.h
#define?__UNIQUE_ID(prefix)?__PASTE(__PASTE(__UNIQUE_ID_,?prefix),?__COUNTER__)
//?include/linux/compiler_types.h
#define?___PASTE(a,b)?a##b
#define?__PASTE(a,b)?___PASTE(a,b)
上面是MODULE_INFO的完整定義,其目的是為了生成唯一的字符串。
下面我們舉個例子:
MODULE_AUTHOR(donge)
//?#define?MODULE_AUTHOR(_author)?MODULE_INFO(author,?_author)
MODULE_INFO(author,?donge)
????
//?#define?MODULE_INFO(tag,?info)?__MODULE_INFO(tag,?tag,?info)
__MODULE_INFO(author,?author,?donge)
????
//#define?__MODULE_INFO(tag,?name,?info)???????\
//static?const?char?__UNIQUE_ID(name)[]???????\
//??__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))???\
//??=?__stringify(tag)?"="?info
static?const?char?__UNIQUE_ID(author)[]??\
????__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))?\
????=?__stringify(author)?"="?donge
//?#define?__UNIQUE_ID(prefix)?__PASTE(__PASTE(__UNIQUE_ID_,?prefix),?__COUNTER__)
static?const?char?__PASTE(__PASTE(__UNIQUE_ID_,?author),?__COUNTER__)[]??\
????__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))?\
????=?__stringify(author)?"="?donge
????
//?#define?___PASTE(a,b)?a##b
//?#define?__PASTE(a,b)?___PASTE(a,b)
static?const?char?__UNIQUE_ID_author__COUNTER__[]??\
????__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))?\
????=?__stringify(author)?"="?donge
//?__COUNTER__會被展開為一個從0開始的整數(shù),每次調(diào)用都會加一
static?const?char?__UNIQUE_ID_author0[]???\
????__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))?\
????=?__stringify(author)?"="?donge
????
//?#define?__stringify_1(x...)?#x
//?#define?__stringify(x...)???__stringify_1(x)
static?const?char?__UNIQUE_ID_author0[]???\
????__used?__attribute__((section(".modinfo"),?unused,?aligned(1)))?\
????=?"author=donge"
現(xiàn)在我們對這些宏定義了如指掌了吧,下面來分析一下部分屬性的含義
aligned:指定變量或結構域的起始地址對齊(以字節(jié)為單位)
used:通知編譯器在目標文件中保留一個靜態(tài)函數(shù),即使它沒有被引用。
attribute__((used)):被標記在目標文件中,以避免鏈接器刪除未使用的節(jié)。
__attribute__((section(".modinfo"))):將被修飾的變量或函數(shù)編譯到特定的一塊內(nèi)存空間的位置
__attribute__((used)):描述靜態(tài)變量
unused:表明該函數(shù)或者變量可能不使用,避免編譯器產(chǎn)生警告信息。
#和##:我們使用#把宏參數(shù)變?yōu)橐粋€字符串,用##把兩個宏參數(shù)貼合在一起.
?
我們通過MODULE_XXXX設置的信息,怎么去查看呢?通過lsmod xxx.ko命令
[r8-common-vrf?dong@ubuntu?~/WorkSpace/arobot_buildroot/output/r8-common-vrf/build/linux-refs_remotes_origin_r8_develop/drivers/char]$?modinfo?arobot-rp-r8.ko
filename:???????/home/dong/WorkSpace/arobot_buildroot/output/r8-common-vrf/build/linux-refs_remotes_origin_r8_develop/drivers/char/arobot-rp-r8.ko
description:????Arobot?processor?B?driver
author:?????????Amicro
license:????????GPL
alias:??????????of:N*T*Carobot,r8-rpC*
alias:??????????of:N*T*Carobot,r8-rp
depends:????????
intree:?????????Y
name:???????????arobot_rp_r8
vermagic:???????4.19.123?SMP?preempt?mod_unload?ARMv7?p2v8?
?
OK,上文較為詳細介紹了
Kernel內(nèi)部MODULE_INFO的詳細實現(xiàn),還有一些重要的知識點沒有展開介紹,例如:__attribute__((section(".xxx")))的作用,后續(xù)再起一篇文章介紹。
?

