前言
我第一次接触Linux,还是几年前学怎么是去破解别人家的wifi然后做ARP欺骗的那会,用的是Kali Linux。后来没怎么继续钻研也就忘得差不多了。本学期所修的操作系统课要求做编译和替换Linux内核的作业,而自己在实验过程中遇到过很多问题,参考了多篇博客,也踩了很多别人博客里的坑,所以也就写下这篇博客归纳下。
1 准备
1.1 实验环境
Vmware12 + ubuntu10.10(32bits) + linux-2.6.32.71.tar.xz
未采用最新版的原因: 个人觉得对于仅仅是学习Linux内核编译这个过程而言,不需要追求最新的环境,做到理解这个过程就足够了,况且老版本资料相对多一些。
1.2 其他参考链接与下载
在编译过程中,我主要参考了一篇博客,这里也贴出来,方便大家对照学习。**同时ubuntu和内核文件的下载也在下面这篇博客里边,自取。Linux 内核编译(三天吐血经历!)
2 安装Linux
2.1 系统资源分配
在Vmware中安装Linux时要注意设置以下配置参数
1)处理器: 尽量多分配。编译内核的时候能够速度快一些,减少等待时间(如果电脑配置低,真的会等上一两个小时)。
2)内存:2G 足够,操作不卡顿。
3)磁盘:40G 及以上(自己第一次做的时候,按默认分配20G,后来磁盘空间不足,没办法继续后面的操作。而且Linux安装完成后再分配空间会比较麻烦。可以参考这篇文章扩容。
2.2 安装完成
Vmware安装系统很简单,不多解释。值得注意的是,安装完成后,最好保持系统语言为英语,这使得我们之后输入命令变得方便很多。
2.3 复制内核,并解压
1)将内核文件拷贝至/usr/src目录下:
得益于Vmware Tools的支持,我们可以直接将内核文件通过拖拽的方式复制到Linux系统中。
2)打开终端,获得管理员权限:
sudo su
3)解压缩:
cd /usr/src //进入目录
xz -d linux-2.6.32.71.tar.xz //解压成.tar文件
tar xvf linux-2.6.32.71.tar //解压
3 替换内核
3.1 打开sys.c文件
sys.c这个文件中包含了绝大部分的系统调用函数的实现。
gedit /usr/src/linux-2.6.32.71/kernel/sys.c
gedit是一款文本编辑器,带有语法高亮。
3.2 在sys.c文件的末尾增加系统调用
我们要增加的是下面这个函数方法,在调用后打印一行文字。
asmlinkage int sys_mycall(int number)
{
printk("Hello my linux world!");
return number;
}
完成更改后,保存并退出。
3.3 注册系统调用
Gedit /usr/src/linux-2.6.32.71/arch/x86/kernel/syscall_table_ 32.S
在文件末尾添加变量:
.long sys_mycall
完成更改后,保存并退出。
3.4 设置系统号
gedit /usr/src/linux-2.6.32.71/arch/x86/include/asm/unistd_32.h
1)在#define __NR_xxxxx之后添加:
#define __NR_mycall 337
2)将#define _NR_syscalls 337改为338
要保证_NR_syscalls相当于系统调用边界,所有系统号都要小于它。
4 编译内核
逐条键入以下命令,确保所有命令正确运行无错误。
cd /usr/src/linux-2.6.32.71 //进入目录
make mrproper
make clean
make oldconfig
make bzImage //编译内核
make modules //编译模块
make modules_install //安装模块
make install //生成config
这个过程中耗时最久的是make bzImage与make modules。大概耗时会超过一个小时,所以可以休息下。如果我们自定义的系统调用存在错误,会在这个编译过程中报告错误并中断。
(在前面贴的那篇博客中,并没有make install这步,导致后面更新grub引导表没有新内核的.config文件,无法继续进行下一步,后来通过查看了其他几篇博客才找到这个问题。这也提醒了我,自己在写完博客后一定要反复检查自己的博客,及时修正内容,少让读者走弯路。)
5 拷贝内核
5.1 查看编译完成结果
进入/lib/modules中,左边没有generic的文件夹是新的内核模块
5.2 拷贝内核到/boot中
cp /usr/src/linux-2.6.32.71/arch/i386/boot/bzImage /boot/vmlinuz-2.6.32.71-mykernel
5.3 创建initrd文件
initrd文件中包含了系统的各种可执行文件和驱动程序。
mkinitramfs -o /boot/initrd.img-2.6.32.71
5.4 更新grub引导表
修改grub引导表,以引导启动新的内核版本。
这个是非常重要的一步,如果没有正确的完成,可能会导致系统重启后,无法再进入系统!然后就正很苦逼的将以上操作全部重来!所以要非常非常仔细。
gedit /boot/grub/grub.cfg //打开引导表文件
1)找到我们所需要修改的部分:
需要修改的部分包含在一下的结构中,其中共有1、2两段代码
### BEGIN/etc/grub.d/10_linux ###
1……
2……
### END/etc/grub.d/10_linux ###
2)复制begin与end之间的1、2代码段,并粘贴到begin之后
### BEGIN/etc/grub.d/10_linux ###
N1……
N2……
1……
2……
### END/etc/grub.d/10_linux ###
3)修改N1与N2中的版本号为新内核的版本号(红色字体部分)
menuentry ‘Ubuntu, with Linux 2.6.32.71 ’ --class ubuntu --class gnu-linux --class gnu --class os
{
recordfail
insmod part_msdos
insmod ext2
set root=’(hd0,msdos1)’
search --no-floppy --fs-uuid --set dd02b80e-a0f5-4a38-b6a5-bbab00e394bb
linux /boot/vmlinuz-2.6.32.71-mykernel root=UUID=dd02b80e-a0f5-4a38-b6a5-bbab00e394bb ro quiet splash
initrd /boot/initrd.img-2.6.32.71
}
menuentry ‘Ubuntu, with Linux 2.6.32.71 (recovery mode)’ --class ubuntu --class gnu-linux --class gnu --class os
{
recordfail
insmod part_msdos
insmod ext2
set root=’(hd0,msdos1)’
search --no-floppy --fs-uuid --set dd02b80e-a0f5-4a38-b6a5-bbab00e394bb
echo ‘Loading Linux 2.6.32.71 …’
linux /boot/vmlinuz-2.6.32.71-mykernel root=UUID=dd02b80e-a0f5-4a38-b6a5-bbab00e394bb ro single
echo ‘Loading initial ramdisk …’
initrd /boot/initrd.img-2.6.32.71
}
修改完成后,保存并退出。
6 最后一步
6.1 备份initrid文件
cd /boot
cp initrd.img-2.6.32.71 initrd-2.6.32.71.old
6.2 修改initrid文件
命令较多,注意命令里的空格
depmod -a
update-initramfs -k 2.6.32.71 -c
cd /tmp
gzip -dc /boot/initrd.img-2.6.32.71| cpio -id
touch lib/modules/2.6.32.71/modules.dep
find ./ | cpio -H newc -o > /boot/initrd.img-2.6.32.71.new
gzip /boot/initrd.img-2.6.32.71.new
cd /boot
mv initrd.img-2.6.32.71.new.gz initrd.img-2.6.32.71
执行完以上命令,替换和编译都已经全部完成了,下面可以重启系统,查看结果了。
reboot //重启
7 查看结果
7.1 查看内核版本
sudo su //获得管理员权限
uname -a
7.2 测试自定义系统调用
1)在终端中打开gedit工具
gedit
2)键入测试代码
#include<stdio.h>
int main()
{
syscall(337, 1);
return 0;
}
保存为mytest.c,位置为Desktop
3)进入桌面,编译程序
cd /Desktop
gcc -o mytest mytest.c
./mytest
4)运行程序
dmesg -c
5)查看结果
8 结语
以上便完成了Linux内核的编译和替换。个人对linux的理解不深,所以如果以上内容存在错误与不足,非常欢迎评论指出。 另外除了文中提到的一些细节,还有很多坑也遇到过没有细说,环境不同所遇到的问题也不尽相同,欢迎留言评论。