不知大家有沒(méi)有想過(guò),在一個(gè)內(nèi)核模塊代碼中,會(huì)用到printk
函數(shù),而這個(gè)函數(shù)不是我們實(shí)現(xiàn)的,它是內(nèi)核代碼的一部分,但我們?yōu)槭裁茨軌蚓幾g通過(guò)呢?
我們的代碼之所以能夠編譯通過(guò),是因?yàn)閷?duì)模塊的編譯 僅僅是編譯,并沒(méi)有鏈接 。
編譯出來(lái)的.ko
文件是一個(gè)普通的ELF
文件 ,使用file
命令和nm
命令,我們可以看到相關(guān)的信息:
# file vser.ko
vser.ko ELF 32-bit LSB relocatable, Intel 80386, vserion 1 (SYSV), BuildID[sha1]=0x09ca747e6f75c65v19a5da9102113v98d7cea24, not stripped
# nm vser.ko
......
00000004 d port
U printk
00000000 t vser_exit
00000000 t vser_init
vser_init
和vser_exit
分別是模塊的入口函數(shù)和出口函數(shù),使用nm
命令查看模塊目標(biāo)文件的符號(hào)信息時(shí),可以看到vser_exit
和vser_init
的符號(hào)類型是t
,表示它們是 函數(shù) 。
而printk
的 符號(hào)類型是U
,表示它是一個(gè) 未決符號(hào) 。意思是說(shuō)在編譯階段不知道這個(gè)符號(hào)的地址,因?yàn)樗欢x在其他文件中,沒(méi)有放在模塊代碼一起編譯。
那printk函數(shù)的地址問(wèn)題怎么解決呢?答案是用EXPORT_SYMBOL
宏將printk
導(dǎo)出即可。
EXPORT_SYMBOL導(dǎo)出符號(hào)
大致原理:利用EXPORT_SYMBOL
宏生成一個(gè)特定的結(jié)構(gòu)并放在ELF
文件的一個(gè)特定段中,在 內(nèi)核的啟動(dòng)過(guò)程中,會(huì)將符號(hào)的確切地址填充到這個(gè)結(jié)構(gòu)的特定成員中 。
模塊加載時(shí),加載程序?qū)⑷ヌ幚砦礇Q符號(hào),在特殊段中搜索符號(hào)的名字,如果找到,則將獲得的地址填充在被加載模塊的相應(yīng)段中,這樣符號(hào)的地址就可以確定。
使用這種方式處理未決符號(hào),其實(shí)相當(dāng)于把鏈接的過(guò)程推后,進(jìn)行了動(dòng)態(tài)鏈接,和普通的應(yīng)用程序使用共享庫(kù)函數(shù)的道理是類似的 ??梢园l(fā)現(xiàn),內(nèi)核將會(huì)有大量的符號(hào)導(dǎo)出,為模塊提供了豐富的基礎(chǔ)設(shè)施。
-
內(nèi)核
+關(guān)注
關(guān)注
3文章
1416瀏覽量
41442 -
Linux
+關(guān)注
關(guān)注
87文章
11511瀏覽量
213828 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4381瀏覽量
64893 -
編譯
+關(guān)注
關(guān)注
0文章
679瀏覽量
34000
發(fā)布評(píng)論請(qǐng)先 登錄
C代碼實(shí)現(xiàn)程序的跳轉(zhuǎn)|函數(shù)指針
Linux內(nèi)核學(xué)習(xí)筆記:printk調(diào)試
四種獲取內(nèi)核函數(shù)地址的方法

評(píng)論