操作系统实验作业,顺便记录一下过程
就不具体说一些概念了。
通过分析Linux内核源代码和新增一个系统调用的方式,达到对操作系统软件结构及其系统调用实现原理的深入理解,并基本掌握操作系统的改造方法
VM虚拟机上搭建的 Ubuntu18.04
编译的内核是 linux4.16.10 版本
可以根据需要去官网下载,给出2个内核版本
linux-4.16.10.tar.xz
inux-4.16.8.tar.gz
先安装相关的依赖
sudo apt-get install build-essential
sudo apt-get install kernel-package
sudo apt-get install libncurses5-dev
sudo apt-get install flex // flex bsion 防止后面一些报错
sudo apt-get install bison
解压内核
把下载好的内核移动到/usr/src/
上
sudo mv '文件路径'/linux-4.16.10.tar.xz /usr/src/
把下载好的内核解压
cd /usr/src
sudo tar -xvf /usr/src/linux-4.16.10.tar.xz
如果要确定自己的内核版本,可以在终端输入命令
uname -r
cd /usr/src/linux-4.16.10/kernel
编写我们的系统调用
打开sys.c
文件 (三选一 后面就不都写出来了 都写成gedit
看个人喜好)
sudo gedit sys.c gedit只能用在图形界面上
sudo vi sys.c
sudo vim sys.c
添加一个我们定义的函数作为系统调用(简单示范打印一个hello world)
asmlinkage long sys_helloworld(void){
printk( "helloworld!");
return 1;
}
cd /usr/src/linux-4.16.10/arch/x86/include/asm/
sudo gedit syscalls.h
添加一个声明
asmlinkage long sys_helloworld(void);
添加系统调用id编号
进入/usr/src/linux-4.16.10/arch/x86/syscalls
目录,打开文件syscall_64.tbl
cd /usr/src/linux-4.16.10/arch/x86/entry/syscalls
sudo gedit syscall_64.tbl
添加自己的系统调用号
333 64 helloworld sys_helloworld
注意,这里查看一下自己是64还是32位的,如果不确定可以在syscall_32.tbl里也添加一下
编译内核
依次输入这四条语句
sudo make mrproper
sudo make clean
sudo make menuconfig
sudo make -j2 (根据自己的线程来设置 4核4线程就-j4 线程越多编译越快)
在sudo make menuconfig
时
有的可能会报错,可能是因为窗口太小显示不了图形界面,建议先把窗口最大化
这里直接save
保存就好 然后exit
退出
make
编译的时间超级漫长,大概2到3个小时 可以挂着去干别的了
注意一下,内存空间是否足够,我一开始没有注意到这些问题,用虚拟机编译到最后,磁盘的空间不够了,忍痛删除了一些东西,释放空间,才最后编译安装完成,大家一定要吸取我的教训,磁盘小的话,先做好备份,转移到大的空间在开始编译。
安装内核
简单执行即可,没什么好说的
sudo make modules_install
sudo make install
重启虚拟机或系统
reboot
开机时 一直长按shift
进入如下画面
选高级选项
在选定我们的内核进入
中途我出现了这样的问题,卡在这个logo上 就是进不去系统
(如果没有这个问题,直接往下看就行了 忽视)
这个问题困扰了我很久,正常不去但是能进去恢复系统,在网上查询也无果,我认为可能是我编译时出现了问题,前前后后又重新编译了几次,花费不少时间,后来一顿瞎操作就进到内核里了,这里写出来,仅供大家参考
如果出现别的问题也请善用百度,我这里也就提出我实验中发现的问题,如果实在不行可以尝试重新编译或者换一下别的版本的内核。
这里选recovery mode
恢复进入
直接选第一个一直ok
就进入了
验证系统调用是否成功
下面编写一个函数,来试试我们自己编写的函数调用
gedit test.c
test.c
#include
#include
int main()
{
syscall(333); //上面自己定义的系统调用编号
return 0;
}
编译一下
gcc test.c
因为我们的系统调用函数使用printk打印 会显示在日志上,而不是控制台
我们先清空一下日志 方便观察
sudo dmesg -C 清空日志
dmesg 查看日志
本来认为是一个简单的小实验,自己上手操作时,会出现各种问题,前前后后也花了不少时间完成,在网上查了不少资料,借鉴大佬的操作流程,站在巨人的肩膀上向前推进。这次实验,新学到了许多关于系统调用的新知识,用户栈到内核栈的转换,系统调用表的查询等。同时,自己也近距离的接触了一下内核,对内核进行一些简单的修改,使高深莫测的内核,变得不再那么遥不可及,熟悉linux的同时,也提升了自己的调试能力和自己的耐心,完成了这个实验。