Linux编译内核记

647 查看

前段时间学校某课程(你猜啥课程~)要求进行简单的linux内核编译,并添加自己的系统调用,对于Linux小白来说这可不是件简单的事,的确话费不少时间和精力。趁此博客终于过了之际,来记录一下~

0x01 实验前的准备

环境说明:

  • Ubuntu10.04(过高版本刚开始编译各种错误)
  • linux-2.6.39(差不多这个版本编译起来成功概率大点吧oo)
apt-get install build-essential kernel-package libncurses5-dev libqt3-headers

工具说明:

  • build-essential (基本的编程库(gcc, make等)
  • kernel-package (Debian 系统里生成 kernel-image 的一些配置文件和工具)
  • libncurses5-dev (meke menuconfig要调用的)
  • libqt3-headers (make xconfig要调用的)->这个应该是没有用到的,至少目前是。。

下载内核源代码:

wget http://www.kernel.org/pub/linux/kernel/linux-2.6.39.tar.bz2
tar -jxvf linux-2.6.39.tar.bz2

说明:因为我下载的是tar.bz2格式的文件,所以解压命令参数是这个,如果下载的是不同格式,解压命令可能不同将内核文件解压到usr/src下,自动生成文件夹linux-2.6.39

0x02 添加系统调用

step1

# gedit /usr/src/linux-2.6.39/kernel/sys.c 


asmlinkage int sys_mycall(int number) {
      printk(KERN_EMERG "hello, world");    
      return number;  
}

打开sys.c文件,在最后添加这样一个函数(最好加上KERN_EMERG,这个表明你的printk优先级较高,不然很有可能在后面看不到想看到的结果

step2

#gedit /usr/src/linux-2.6.39/arch/x86/kernel/syscall_table_32.S

这里我们将223行.long sys_ni_syscall改为.long sys_mycall
名称和刚刚定义的函数对应,格式自行模仿~

step3

#gedit /usr/src/linux-2.6.39/arch/x86/include/asm/unistd_32.h

增加一行,对应上面的223

#define __NR_mycall  223

名称同样也是对应的

0x03 开始编译啦

step1

把正在使用中的内核配置文件/boot/linux-2.6.39-generic 拷到/usr/src/linux-2.6.39/.config目录下

cp /boot/config-2.6.32-21-generic  /usr/src/linux-2.6.39/.config

我这个版本自带内核版本是3.6.32-21,大家的可以去boot/目录下查看

step2

make menuconfig

终端会弹出一个配置界面
注意主菜单最后有两项:

load a kernel configuration...
save a kernel configuration...

先选第一项load ....,意思是,利用当前的内核配置详单来设置将要编译的内核,然后选save这一项保存,最后退出配置界面。

step3

执行:

sudo make mrproper  

(清除以前曾经编译过的旧文件,如果你是第一次编译,可不执行)

执行:

sudo make -j2

然后:

sudo make install  
sudo make modules  (编译模块)
sudo make modules_install  (安装模块)

最后创建initrd文件:

mkinitramfs -o /boot/initrd.img-2.6.39

执行

update-grub2

这样刚编译成功的内核就加入到了grub文件中,也就是可以启动了~

打开grub.cfg文件,将timeout改为10,这样启动时就有十秒时间来选择启动哪个内核了。

这个执行完,按理说编译应该成功了,但是你启动会提示你有错误,启动不了,这样你可以进入以前内核,执行下列命令,就可以正常启动了(所以说不如第一次编译完就执行这些命令,要是非要看看它是怎么抽风拒绝启动的,倒是也可以尝试一下哇)

cd /boot
cp initrd.img-2.6.39 initrd-2.6.39.old (先做一个备份以防万一,哈哈)
depmod -a
update-initramfs -k 2.6.39 -c
cd /tmp
gzip -dc /boot/initrd.img-2.6.39| cpio -id
touch lib/modules/2.6.39/modules.dep
find ./ | cpio -H newc -o > /boot/initrd.img-2.6.39.new
gzip /boot/initrd.img-2.6.39.new
cd /boot
mv initrd.img-2.6.39.new.gz initrd.img-2.6.39

以上所以命令只针对我这个内核版本,如若是其他版本,可以照这个更改~~

0x04 编写测试函数及总结

#include<stdio.h>

int main(){
  syscall(223,1);
  return 0;
}

写完这个测试函数,再用gcc命令编译一下,再dmesg -c一下,你猜会看到啥?哈哈,就是熟悉的“hello world”,听说你不信?那就赶紧自己去试试吧~

结语

杀死无数脑细胞的任务总算完成了,发现segmentfault写起来还是蛮舒心的,对了,要是第一次编译成功后,后面修改了系统调用后,直接从make modules开始做起就好,这样就能省不少时间,不然那个编译时间。。。谁用谁知道啊真的是。。