前段时间学校某课程(你猜啥课程~)要求进行简单的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开始做起就好,这样就能省不少时间,不然那个编译时间。。。谁用谁知道啊真的是。。