关于__init、__initdata和__exit、__exitdata的学习笔记
生活随笔
收集整理的這篇文章主要介紹了
关于__init、__initdata和__exit、__exitdata的学习笔记
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
由于4年前對于C語言和Linux的知識貧乏,所以當時對于模塊中的函數定義沒有細看。這次在溫習《LDD3》的時候,重新看了一下關于__init、__initdata和__exit、__exitdata的知識,記錄如下:
對于__init、__initdata和__exit、__exitdata的定義位于<linux/init.h>,這些宏定義的作用是告訴編譯器將這些函數或者數據放入相應的section中,而在模塊加載的階段,.ko文件中的代碼和數據的加載區域是根據section來加載的。
比如:如果函數的定義中帶有__init,那么這個函數的所有代碼會被放入.init.text的section中。 如果函數的定義中帶有__initdata,那么這個函數的所有代碼會被放入.init.data的section中。
之所以要使用這個宏定義,其中一個原因是標記為初始化的函數和數據,表明該函數和數據僅在初始化期間使用。在模塊裝載之后,模塊裝載就會將初始化函數扔掉。這樣可以將該函數占用的內存釋放出來。
這種釋放根據是否編譯進內核是有區別的: (1)模塊編譯進內核:所有的初始化數據和函數都是在系統啟動的最后階段,在所有模塊都初始化完成以后被內核統一釋放的。所有你一般可以在內核啟動信息的后面看到:
PHY: 0:01 - Link is Up - 100/Full VFS: Mounted root (nfs filesystem) on device 0:14. devtmpfs: mounted Freeing init memory: 196K INIT: version 2.86 booting
(2)獨立的模塊:模塊是通過module-init-tool中的insmod的程序利用系統調用來掛載的,而所有的初始化數據和函數都是被這個系統調用所使用的,在模塊掛載完成并初始化過后,由系統調用來完成對初始化數據和函數所占空間的釋放。
所以對于將內核驅動代碼中的函數和數據定義為“初始化”時需要注意:不要將驅動定義的文件方法(如 open、read、write、close)或者驅動在實際工作中需要使用的函數和數據定義為“初始化”屬性,因為在驅動初始化后這些東東就已經被釋放了,如果使用了就會Oops。
有些網上的文章中寫到: __init宏使內建模塊中的init函數在執行完成后釋放掉,不過可裝載的模塊不受影響。
這個是錯誤的,這些“初始化”宏同樣影響可裝載模塊。從模塊裝載的系統調用源碼中你可以找到釋放的地方,他釋放的是整個“初始化”section。具體的情況請參考《深入Linux內核構架》的《第七章 模塊》
從代碼上可以證明“初始化”宏同樣影響可裝載模塊,從實驗中同樣可以,實驗步驟: (1)在一個簡單的字符驅動中定義一個“初始化”字符串,并在模塊初始化時打印出來。在驅動的其他方法中也試圖打印這個字符串,如果這個方法被系統調用執行了,那么你就得到了一個Oops。 (2)去掉這個字符串定義時的“初始化”宏,再做一邊實驗,字符串依然可以被打印出來。
對于__init、__initdata和__exit、__exitdata的定義位于<linux/init.h>,這些宏定義的作用是告訴編譯器將這些函數或者數據放入相應的section中,而在模塊加載的階段,.ko文件中的代碼和數據的加載區域是根據section來加載的。
比如:如果函數的定義中帶有__init,那么這個函數的所有代碼會被放入.init.text的section中。 如果函數的定義中帶有__initdata,那么這個函數的所有代碼會被放入.init.data的section中。
之所以要使用這個宏定義,其中一個原因是標記為初始化的函數和數據,表明該函數和數據僅在初始化期間使用。在模塊裝載之后,模塊裝載就會將初始化函數扔掉。這樣可以將該函數占用的內存釋放出來。
這種釋放根據是否編譯進內核是有區別的: (1)模塊編譯進內核:所有的初始化數據和函數都是在系統啟動的最后階段,在所有模塊都初始化完成以后被內核統一釋放的。所有你一般可以在內核啟動信息的后面看到:
所以對于將內核驅動代碼中的函數和數據定義為“初始化”時需要注意:不要將驅動定義的文件方法(如 open、read、write、close)或者驅動在實際工作中需要使用的函數和數據定義為“初始化”屬性,因為在驅動初始化后這些東東就已經被釋放了,如果使用了就會Oops。
有些網上的文章中寫到:
從代碼上可以證明“初始化”宏同樣影響可裝載模塊,從實驗中同樣可以,實驗步驟: (1)在一個簡單的字符驅動中定義一個“初始化”字符串,并在模塊初始化時打印出來。在驅動的其他方法中也試圖打印這個字符串,如果這個方法被系統調用執行了,那么你就得到了一個Oops。 (2)去掉這個字符串定義時的“初始化”宏,再做一邊實驗,字符串依然可以被打印出來。
總結
以上是生活随笔為你收集整理的关于__init、__initdata和__exit、__exitdata的学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下的LED子系统
- 下一篇: Linux下的Backlight子系统