不知大家有沒有想過,在一個內核模塊代碼中,會用到printk函數(shù),而這個函數(shù)不是我們實現(xiàn)的,它是內核代碼的一部分,但我們?yōu)槭裁茨軌蚓幾g通過呢?
我們的代碼之所以能夠編譯通過,是因為對模塊的編譯 僅僅是編譯,并沒有鏈接 。
編譯出來的.ko文件是一個普通的ELF文件 ,使用file命令和nm命令,我們可以看到相關的信息:
# 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命令查看模塊目標文件的符號信息時,可以看到vser_exit和vser_init的符號類型是t,表示它們是 函數(shù) 。
而printk的 符號類型是U,表示它是一個 未決符號 。意思是說在編譯階段不知道這個符號的地址,因為它被定義在其他文件中,沒有放在模塊代碼一起編譯。
那printk函數(shù)的地址問題怎么解決呢?答案是用EXPORT_SYMBOL宏將printk導出即可。
EXPORT_SYMBOL導出符號
大致原理:利用EXPORT_SYMBOL宏生成一個特定的結構并放在ELF文件的一個特定段中,在 內核的啟動過程中,會將符號的確切地址填充到這個結構的特定成員中 。
模塊加載時,加載程序將去處理未決符號,在特殊段中搜索符號的名字,如果找到,則將獲得的地址填充在被加載模塊的相應段中,這樣符號的地址就可以確定。
使用這種方式處理未決符號,其實相當于把鏈接的過程推后,進行了動態(tài)鏈接,和普通的應用程序使用共享庫函數(shù)的道理是類似的 。可以發(fā)現(xiàn),內核將會有大量的符號導出,為模塊提供了豐富的基礎設施。
-
內核
+關注
關注
4文章
1436瀏覽量
42499 -
Linux
+關注
關注
88文章
11628瀏覽量
218012 -
函數(shù)
+關注
關注
3文章
4406瀏覽量
66851 -
編譯
+關注
關注
0文章
688瀏覽量
34950
發(fā)布評論請先 登錄
C代碼實現(xiàn)程序的跳轉|函數(shù)指針
Linux內核學習筆記:printk調試
printk()函數(shù)的總結
linux內核打印函數(shù)printk的方法
如何配置和使用Linux內核printk功能
內核日志及printk結構淺析
你知道Linux內核調試關鍵技術之一的printk?
Linux中的Printk與dmesg功能
使用LPNDR_ReadGlobalInfo函數(shù)塊讀取IP地址和MAC地址
C語言如何獲得自身定義函數(shù)的實際地址和大小嗎
如何使用函數(shù)指針?
Linux內核pr_xx()函數(shù)封裝
Linux內核printk日志級別全解析:從參數(shù)解讀到實操配置

printk函數(shù)的地址問題怎么解決
評論