编译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)文档。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章