Linux 驱动开发之内核模块开发(四)—— 符号表的导出
?Linux內核頭文件提供了一個方便的方法用來管理符號的對模塊外部的可見性,因此減少了命名空間的污染(命名空間的名稱可能會與內核其他地方定義的名稱沖突),并且適當信息隱藏。 如果你的模塊需要輸出符號給其他模塊使用,應當使用下面的宏定義:
EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);?? //只適用于包含GPL許可權的模塊;
? ? ?這兩個宏均用于將給定的符號導出到模塊外. _GPL版本的宏定義只能使符號對GPL許可的模塊可用。?符號必須在模塊文件的全局部分導出,不能在函數中導出,這是因為上述這兩個宏將被擴展成一個特殊用途的聲明,而該變量必須是全局的。這個變量存儲于模塊的一個特殊的可執行部分(一個"ELF段" ),在裝載時,內核通過這個段來尋找模塊導出的變量(感興趣的讀者可以看<linux/module.h>獲知更詳細的信息)。
一、宏定義EXPORT_SYMBOL分析
1、源碼
[cpp]?view plaincopy
在分析前,先了解如下相關知識:
1)#運算符,##運算符
? ? ?通常在宏定義中使用#來創建字符串 #abc就表示字符串”abc”等。
? ? ##運算符稱為預處理器的粘合劑,用來替換粘合兩個不同的符號,
如:#define xName (n) ?x##n
則xName(4) ?則變為x4
2)gcc的 __attribute__ 屬性:
? ? ?__attribute__((section(“section_name”)))的作用是將指定的函數或變量放入到名為”section_name”的段中。
? ? __attribute__屬性添加可以在函數或變量定義的時候直接加入在定義語句中。
如:
int myvar__attribute__((section("mydata"))) = 0;
表示定義了整形變量myvar=0;并且將該變量存放到名為”mydata”的section中
關于gcc_attribute詳解可以參考:http://blog.sina.com.cn/s/blog_661314940100qujt.html
2、EXPORT_SYMBOL的作用是什么?
? ? ? ?EXPORT_SYMBOL標簽內定義的函數或者符號對全部內核代碼公開,不用修改內核代碼就可以在您的內核模塊中直接調用,即使用EXPORT_SYMBOL可以將一個函數以符號的方式導出給其他模塊使用。
? ? ? ?這里要和System.map做一下對比:System.map 中的是連接時的函數地址。連接完成以后,在2.6內核運行過程中,是不知道哪個符號在哪個地址的。
? ? ? ?EXPORT_SYMBOL的符號,是把這些符號和對應的地址保存起來,在內核運行的過程中,可以找到這些符號對應的地址。而模塊在加載過程中,其本質就是能動態連接到內核,如果在模塊中引用了內核或其它模塊的符號,就要EXPORT_SYMBOL這些符號,這樣才能找到對應的地址連接。
二、 EXPORT_SYMBOL使用方法
第一、在模塊函數定義之后使用EXPORT_SYMBOL(函數名)
第二、在調用該函數的模塊中使用extern對之聲明
第三、首先加載定義該函數的模塊,再加載調用該函數的模塊
要調用別的模塊實現的函數接口和全局變量,就要導出符號?/usr/src/linux-headers-2.6.32-33-generic/Module.symvers
| A | B |
| static?int?num?=10; static?void?show(void) { printk("%d??\n",num); } EXPORT_SYMBOL(show); | extern?void?show(void); |
函數A先將show() 函數導出,函數B 使用extern 對其聲明,要注意:
a -- 編譯a模塊后,要將?Module.symvers?拷貝到b模塊下
b -- 然后才能編譯b模塊
c -- 加載:先加載a模塊,再加載b模塊
d -- 卸載:先卸載b模塊,再卸載a模塊
三、示例
代碼a ,hello.c [cpp]?view plaincopy
代碼b show.c [cpp]?view plaincopy
編譯后加載模塊,卸載模塊,可以用?dmesg?查看內核打印信息。
總結
以上是生活随笔為你收集整理的Linux 驱动开发之内核模块开发(四)—— 符号表的导出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux 系统应用编程——网络编程(高
- 下一篇: CC254x--API