不知大家有沒有想過,在一個(gè)內(nèi)核模塊代碼中,會用到printk
函數(shù),而這個(gè)函數(shù)不是我們實(shí)現(xiàn)的,它是內(nèi)核代碼的一部分,但我們?yōu)槭裁茨軌蚓幾g通過呢?
我們的代碼之所以能夠編譯通過,是因?yàn)閷δK的編譯 僅僅是編譯,并沒有鏈接 。
編譯出來的.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)文件的符號信息時(shí),可以看到vser_exit
和vser_init
的符號類型是t
,表示它們是 函數(shù) 。
而printk
的 符號類型是U
,表示它是一個(gè) 未決符號 。意思是說在編譯階段不知道這個(gè)符號的地址,因?yàn)樗欢x在其他文件中,沒有放在模塊代碼一起編譯。
那printk函數(shù)的地址問題怎么解決呢?答案是用EXPORT_SYMBOL
宏將printk
導(dǎo)出即可。
EXPORT_SYMBOL導(dǎo)出符號
大致原理:利用EXPORT_SYMBOL
宏生成一個(gè)特定的結(jié)構(gòu)并放在ELF
文件的一個(gè)特定段中,在 內(nèi)核的啟動(dòng)過程中,會將符號的確切地址填充到這個(gè)結(jié)構(gòu)的特定成員中 。
模塊加載時(shí),加載程序?qū)⑷ヌ幚砦礇Q符號,在特殊段中搜索符號的名字,如果找到,則將獲得的地址填充在被加載模塊的相應(yīng)段中,這樣符號的地址就可以確定。
使用這種方式處理未決符號,其實(shí)相當(dāng)于把鏈接的過程推后,進(jìn)行了動(dòng)態(tài)鏈接,和普通的應(yīng)用程序使用共享庫函數(shù)的道理是類似的 。可以發(fā)現(xiàn),內(nèi)核將會有大量的符號導(dǎo)出,為模塊提供了豐富的基礎(chǔ)設(shè)施。
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。
舉報(bào)投訴
相關(guān)推薦
凡是學(xué)過C語言函數(shù)的應(yīng)該都知道,函數(shù)名其實(shí)就是個(gè)地址,是函數(shù)的入口地址。如果用 %p 來輸出函數(shù)
發(fā)表于 01-17 09:26
?1400次閱讀
很多內(nèi)核開發(fā)者喜歡的調(diào)試工具是printk,在Linux內(nèi)核中,使用printk()函數(shù)來打印信息,它與C庫的printf()函數(shù)類似。
發(fā)表于 06-01 15:14
?1082次閱讀
在內(nèi)核調(diào)試中,經(jīng)常需要知道某個(gè)函數(shù)的地址,或者根據(jù)函數(shù)地址找到對應(yīng)的函數(shù),從而進(jìn)行更深一步的debug。
發(fā)表于 11-17 16:58
?1218次閱讀
我們在使用printk()函數(shù)中使用日志級別為的是使編程人員在編程過程中自定義地進(jìn)行信息的輸出,更加容易地掌握系統(tǒng)當(dāng)前的狀況。對程序的調(diào)試起到了很重要的作用。(下文中的日志級別和控制臺日志控制級別
發(fā)表于 07-09 03:47
1.linux內(nèi)核打印函數(shù)printk一、函數(shù)有頭文件二、定義的關(guān)鍵宏三、函數(shù)原型合理的創(chuàng)建標(biāo)題,有助于目錄的生成如何改變文本的樣式插入鏈接與圖片如何插入一段漂亮的代碼片生成一個(gè)適合你
發(fā)表于 12-20 07:02
了解如何配置和使用Linux內(nèi)核printk功能,包括其動(dòng)態(tài)調(diào)試功能。
這樣可以選擇性地打印調(diào)試消息,而無需重新編譯內(nèi)核。
發(fā)表于 11-27 06:40
?3058次閱讀
做DPDK項(xiàng)目時(shí),調(diào)試rte_kni.ko時(shí),發(fā)現(xiàn)printk并不會向我們想想的那樣把log信息顯示在我們的終端上。
發(fā)表于 04-22 17:45
?1099次閱讀
在內(nèi)核調(diào)試技術(shù)之中,最簡單的就是printk的使用了,它的用法和C語言應(yīng)用程序中的printf使用類似,在應(yīng)用程序中依靠的是stdio.h中的庫,而在linux內(nèi)核中沒有這個(gè)庫,所以在linux內(nèi)核中,使用這個(gè)printk就要對內(nèi)核的實(shí)現(xiàn)有一定的了解。
發(fā)表于 05-10 11:18
?1661次閱讀
結(jié):??????? Printf在終端顯示,printk()函數(shù)為內(nèi)核空間里邊的信息打印函數(shù),就像c編程時(shí)用的printf()函數(shù)一樣,專供內(nèi)核中的信息展示用,他沒有調(diào)用printf(
發(fā)表于 04-02 14:39
?454次閱讀
PMT函數(shù)與相對絕對地址引
發(fā)表于 05-12 14:47
?0次下載
這篇文章介紹C語言的內(nèi)聯(lián)函數(shù)、遞歸函數(shù)、函數(shù)指針、指針函數(shù)、局部地址、const關(guān)鍵字、extern關(guān)鍵字等知識點(diǎn);這些知識點(diǎn)在實(shí)際項(xiàng)目開發(fā)
發(fā)表于 08-14 10:03
?1637次閱讀
使用 LPNDR_ReadGlobalInfo 函數(shù)塊可以讀取 PROFINET 設(shè)備的 IP 地址和 MAC 地址。
發(fā)表于 11-14 10:09
?3942次閱讀
我們先看地址。C語言無法定義函數(shù)外標(biāo)簽,函數(shù)內(nèi)標(biāo)簽從使用到訪問處處受限,我們好像只剩函數(shù)名可以用。但函數(shù)名表達(dá)式未必等同于
發(fā)表于 12-02 10:52
?1033次閱讀
在程序中定義一個(gè)函數(shù),則編譯時(shí)系統(tǒng)就會為這段代碼分配一段存儲空間,這段存儲空間的首地址稱為函數(shù)的地址,且函數(shù)名代表的就是這個(gè)
發(fā)表于 03-30 15:09
?826次閱讀
pr_xx( )封裝 在使用printk的時(shí)候需要手動(dòng)添加輸出等級KERN_INFO、KERN_WARNING等,這樣還是有些麻煩。因此,Linux內(nèi)核也對printk進(jìn)行了進(jìn)一步的封裝
發(fā)表于 09-27 15:58
?720次閱讀
評論