編譯Linux內核

我們在安裝新內核的時候,通常都會編輯lilo.conf 和grub.conf 文檔。裏面有一段“initrd=/boot/initrd-***.img”(其中的***表示內核的版本號)的我們都很少會注意到,有時候還會發現這一行不要也能夠正常開機。那這個initrd***.img究竟是用來幹什麼的呢? 
   其實initrd***.img是個映像文檔,類似ramdisk,把一段程式打包到img裏,然後在開機的時候在內存裏開闢一段區域,一般是2m,釋放到那裏運行,都是一些初始化的程式,比如sisc_mod、ext3、sd_mod等模塊和insmod、nash等命令。不同內核初始化的img能夠相同,也能夠不同,假如沒有,能夠在grub.conf里加上no initrd,他就跳過initrd的檢測和執行了,以前似乎就沒有,後來纔有的。    
   他的作用是在沒有mount /分區以前,系統要執行一些操作,比如掛載scsi驅動,他就把initrd釋放到內存裏,作一個虛擬的/,然後執行其根目錄下的一個腳本"linuxrc",運行insmod和nash命令掛裝模塊。爲什麼有的時候我們在lilo或grub的配置文檔中不加入該行都能夠正常開機呢?這是因爲我們一般的PC機都沒有使用scsi硬盤等需要先加載其驅動的設備,所以就算沒有initrd***.img也能夠正常開機。但是假如我們要在服務器上爲其編譯新內核那就一定不要忘記也爲其新建一個initrd文檔呀!    
   好,下面來看看怎樣查看initrd***.img裏面的內容和怎樣爲您的新內核創建一個新的initrd.img文檔。 
查看initrd.img: 
initrd***.img雖然後綴是“img”,但其實他是個gz格式的文檔,我們能夠先把他解壓,然後載掛裝到目錄下: 
1、cp initrd.img initrd.gz 
2、guzip initrd.gz 
3、mount -o loop initrd /mnt/floppy 
進入/mnt/floppy目錄,我們就能夠看到initrd***.img文檔的廬山真面目了。 
製作initrd文檔 
當我們編譯了一個新的內核,也不要忘了爲我們的scsi設備做一個新的initrd映像: 
語法: 
mkinitrd 文檔名 內核的目錄名 
示例:  
mkinitrd initrd-2.4.19.img 2.4.19 
initrd-2.4.19.img文檔是自己任意取的,但最好對應自己的內核版本號。 
2.4.19是在/lib/modules中的目錄名,對應內核的版本。 
當然,我們也能夠在掛裝了initrd***.img文檔後直接添加模塊到/lib目錄中,然後修改linuxrc腳本讓其開機進行掛裝。但必須具備一定的shell腳本的能力才行。




 initrd是內核啓動映象,假如沒有這個文檔,有時系統啓動時沒有辦法找到根分區
 initrd.img這樣類似的文檔,是用下面的命令創建面來。我舉例說明:能夠用兩個方法,比如我的系統的內核版本是2.4.20-8
假如我們重編了內核, 就要用下面的兩個命令來生成映像文檔,否則有時系統啓動時會很難找到/根分區。 
mkinitrd /boot/initrd-.2.4.20-8img 2.4.20-8
   這樣就會在/boot 目錄中看到initrd-2.4.20-8.img的文檔,其實您所說的initrd.img就是initrd-2.4.20-8.img文檔的鏈接。
能夠這樣生成
#cd /boot
#ln -s initrd-2.4.20-8.img initrd.img
其實看列一下目錄就知道這是個鏈接。
用這個命令來生成新的內核映象,要使新內核啓動,要改變/etc/grub.conf或lilo.conf才能生效。
[root@linuxsir001 boot]# ll initrd.img
lrwxrwxrwx 1 root root 19 5月 24 13:46 initrd.img -> initrd-2.4.20-8.img
也能夠用下面的命令   new-kernel-pkg --mkinitrd --depmod --install 2.4.20-8
這個命令執行的結果是會生成intrd文檔,也會自動改/etc/grub.conf或lilo.conf,這樣就一步到位使新內核生效。



幾個重要的RedHat Linux內核文檔介紹
   在網絡中,不少服務器採用的是Linux系統。爲了進一步提高服務器的性能,可能需要根據特定的硬件及需求重新編譯Linux內核。編譯Linux內核,需要根據規定的步驟進行,編譯內核過程中涉及到幾個重要的文檔。比如對於RedHat Linux,在/boot目錄下有一些和Linux內核有關的文檔,進入/boot執行。
  編譯過RedHat Linux內核的人對其中的System.map、vmlinuz、initrd-2.4.7-10.img印象可能比較深刻,因爲編譯內核過程中涉及到這些文檔的建立等操作。那麼這幾個文檔是怎麼產生的?又有什麼作用呢?本文對此做些介紹。
  一、vmlinuz
  vmlinuz是可引導的、壓縮的內核。“vm”代表“Virtual Memory”。Linux 支持虛擬內存,不像老的操作系統比如DOS有640KB內存的限制。Linux能夠使用硬盤空間作爲虛擬內存,因此得名“vm”。vmlinuz是可執行的Linux內核,他位於/boot/vmlinuz,他一般是個軟鏈接,比如圖中是vmlinuz-2.4.7-10的軟鏈接。
  vmlinuz的建立有兩種方式。一是編譯內核時通過“make zImage”創建,然後通過:“cp /usr/src/linux-2.4/arch/i386/linux/boot/zImage/boot/vmlinuz”產生。zImage適用於小內核的情況,他的存在是爲了向後的兼容性。
二是內核編譯時通過命令make bzImage創建,然後通過:“cp/usr/src/linux-2.4/arch/i386/linux/boot/bzImage /boot/vmlinuz”產生。bzImage是壓縮的內核映像,需要注意,bzImage不是用bzip2壓縮的,bzImage中的bz容易引起誤解,bz表示“big zImage”。 bzImage中的b是“big”意思。 zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip壓縮的。他們不但是個壓縮文檔,而且在這兩個文檔的開頭部分內嵌有gzip解壓縮代碼。所以您不能用gunzip 或 gzip ?dc解包vmlinuz。
  內核文檔中包含一個微型的gzip用於解壓縮內核並引導他。兩者的不同之處在於,老的zImage解壓縮內核到低端內存(第一個640K),bzImage解壓縮內核到高端內存(1M以上)。假如內核比較小,那麼能夠採用zImage或bzImage之一,兩種方式引導的系統運行時是相同的。大的內核採用bzImage,不能採用zImage。vmlinux是未壓縮的內核,vmlinuz是vmlinux的壓縮文檔。
  二、initrd-x.x.x.img
  initrd是“initial ramdisk”的簡寫。initrd一般被用來臨時的引導硬件到實際內核vmlinuz能夠接管並繼續引導的狀態。圖中的initrd-2.4.7-10.img主要是用於加載ext3等文檔系統及scsi設備的驅動。
  比如,使用的是scsi硬盤,而內核vmlinuz中並沒有這個scsi硬件的驅動,那麼在裝入scsi模塊之前,內核不能加載根文檔系統,但scsi模塊存儲在根文檔系統的/lib/modules下。爲了解決這個問題,能夠引導一個能夠讀實際內核的initrd內核並用initrd修正scsi引導問題。initrd-2.4.7-10.img是用gzip壓縮的文檔,initrd實現加載一些模塊和安裝文檔系統等功能。
  initrd映象文檔是使用mkinitrd創建的。mkinitrd實用程式能夠創建initrd映象文檔。這個命令是RedHat專有的。其他Linux發行版或許有相應的命令。這是個很方便的實用程式。具體情況請看幫助:man mkinitrd下面的命令創建initrd映象文檔。
三、System.map 
  System.map是個特定內核的內核符號表。他是您當前運行的內核的System.map的鏈接。
  內核符號表是怎麼創建的呢? System.map是由“nm vmlinux”產生並且不相關的符號被濾出。
  對於本文中的例子,編譯內核時,System.map創建在/usr/src/linux-2.4/System.map。像下面這樣:
  nm /boot/vmlinux-2.4.7-10 > System.map
  下面幾行來自/usr/src/linux-2.4/Makefile:
  nm vmlinux | grep -v ’\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)’ | sort > System.map
  然後複製到/boot:
  cp /usr/src/linux/System.map /boot/System.map-2.4.7-10
  下圖是System.map文檔的一部分:
  在進行程式設計時,會命名一些變量名或函數名之類的符號。Linux內核是個很複雜的代碼塊,有很多的全局符號。
  Linux內核不使用符號名,而是通過變量或函數的地址來識別變量或函數名。比如不是使用size_t BytesRead這樣的符號,而是像c0343f20這樣引用這個變量。
  對於使用電腦的人來說,更喜歡使用那些像size_t BytesRead這樣的名字,而不喜歡像c0343f20這樣的名字。內核主要是用c寫的,所以編譯器/連接器允許我們編碼時使用符號名,當內核運行時使用地址。
  然而,在有的情況下,我們需要知道符號的地址,或需要知道地址對應的符號。這由符號表來完成,符號表是任何符號連同他們的地址的列表。上圖就是個內核符號表,由上圖可知變量名checkCPUtype在內核地址c01000a5。
  Linux 符號表使用到2個文檔:
  /proc/ksyms
  System.map
  /proc/ksyms是個“proc file”,在內核引導時創建。實際上,他並不真正的是個文檔,他只但是是內核數據的表示,卻給人們是個磁盤文檔的假象,這從他的文檔大小是0能夠看出來。然而,System.map是存在於您的文檔系統上的實際文檔。
  當您編譯一個新內核時,各個符號名的地址要發生變化,您的老的System.map具備的是錯誤的符號信息。每次內核編譯時產生一個新的System.map,您應當用新的System.map來取代老的System.map。
  雖然內核本身並不真正使用System.map,但其他程式比如klogd,lsof和ps等軟件需要一個正確的System.map。假如您使用錯誤的或沒有System.map,klogd的輸出將是不可靠的,這對於排除程式故障會帶來困難。沒有System.map,您可能會面臨一些令人煩惱的提示信息。
  另外少數驅動需要System.map來解析符號,沒有爲您當前運行的特定內核創建的System.map他們就不能正常工作。
  Linux的內核日誌守護進程klogd爲了執行名稱-地址解析,klogd需要使用System.map。System.map應當放在使用他的軟件能夠找到他的地方。執行:man klogd可知,假如沒有將System.map作爲一個變量的位置給klogd,那麼他將按照下面的順序,在三個地方查找System.map:
  /boot/System.map
  /System.map
  /usr/src/linux/System.map
  System.map也有版本信息,klogd能夠智能地查找正確的映象(map)文檔。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章