干货 | Linux内核编译与系统调用教程(基于Ubuntu 18.04,究极无敌简单)

Linux内核编译与系统调用教程(基于Ubuntu 18.04,究极无敌简单)

一、内核与系统调用

1.1 内核(Kernel)简介

  • 内核(Kernel),是一个操作系统的核心。它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。

       众所周知,Linux的一个重要的特点就是开源,所有的内核源程序都可以在路径/usr/src/linux下找到,大部分应用软件也都是遵循GPL而设计的,你都可以获取相应的源程序代码。全世界任何一个软件工程师都可以将自己认为优秀的代码加入到其中,由此引发的一个明显的好处就是Linux修补漏洞的快速以及对最新软件技术的利用。而Linux的内核则是这些特点的最直接的代表。
       由于Linux的源程序是完全公开的,任何人只要遵循GPL,就可以对内核加以修改并发布给他人使用。Linux的开发采用的是集市模型(bazaar,与cathedral–教堂模型–对应),为了确保这些无序的开发过程能够有序地进行,Linux采用了双树系统。一个树是稳定树(stable tree),另一个树是非稳定树(unstable tree)或者开发树(development tree)。一些新特性、实验性改进等都将首先在开发树中进行。
       如果在开发树中所做的改进也可以应用于稳定树,那么在开发树中经过测试以后,在稳定树中将进行相同的改进。一旦开发树经过了足够的发展,开发树就会成为新的稳定树。开发数就体现在源程序的版本号中;源程序版本号的形式为x.y.z:对于稳定树来说,y是偶数;对于开发树来说,y比相应的稳定树大一(因此,是奇数)。

1.2 系统调用简介

       计算机系统的各种硬件资源是有限 的,在现代多任务操作系统上同时运行的多个进程都需要访问这些资源,为了更好的管理这些资源进程是不允许直接操作的,所有对这些资源的访问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call)。在linux中系统调用是用户空间访问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口。

PS: 这里还涉及到了核态与目态的一些知识,大家可以去操作系统原理中找找看,这里就不过多赘述了 :)

二、内核编译目的

       Linux作为一个自由软件,在广大爱好者的支持下,内核版本不断更新。新的内核修订了旧内核的bug,并增加了许多新的特性。如果用户想要使用这些新特性,或想根据自己的系统度身定制一个更高效,更稳定的内核,就需要重新编译内核。
  通常,更新的内核会支持更多的硬件,具备更好的进程管理能力,运行速度更快、 更稳定,并且一般会修复老版本中发现的许多漏洞等,经常性地选择升级更新的系统内核是Linux使用者的必要操作内容。
  为了正确的合理地设置内核编译配置选项,从而只编译系统需要的功能的代码,一般主要有下面四个考虑:

  • 自己定制编译的内核运行更快(具有更少的代码)
  • 系统将拥有更多的内存(内核部分将不会被交换到虚拟内存中)
  • 不需要的功能编译进入内核可能会增加被系统攻击者利用的漏洞
  • 将某种功能编译为模块方式会比编译到内核内的方式速度要慢一些

三、系统调用与内核编译教程(一看就会)

预先说明,我本人使用的18.04 LTS的kernel版本为:5.3.0-51-generic,重新编译的kernel选择了最新的稳定版5.6.15

在这里插入图片描述

3.1 下载内核源代码

进入官网下载所需的内核源码,如图(我选择的是stable 5.6.15)。
kernl
简要说明一下各个版本:

  • mainline:由Linux内核的最早作者Linus Torvalds制作,大概每十周发布一次,是对重大变化的整合以及bug的维护。
  • longterm:长期维护版本。
  • stable:稳定版。

源码下载完成后,解压并拷贝至/usr/src/路径下。

3.2 设置系统调用

首先执行cd /usr/src/你自己解压的源码文件夹切换路径

  1. 在系统调用表中添加自定义的系统调用表项目,执行以下指令:
sudo gedit arch/x86/entry/syscalls/syscall_64.tbl

在不覆盖原有系统调用的前提下(具体可以阅读内部注释),添加自己的系统调用,官方建议以sys_为函数名的首部,如下图所示:
在这里插入图片描述

  1. 将系统调用号定义到相应头文件,执行以下代码:
sudo gedit include/linux/syscalls.h

进行相关定义,如图所示:
在这里插入图片描述

  1. 增加系统调用具体功能,首先执行以下代码:
sudo gedit kernel/sys.c

在末尾实现自定义系统调用的具体功能:
在这里插入图片描述
系统调用部分到这里就结束了。

3.3 重新编译内核

  1. 执行如下命令:
sudo make menuconfig

根据提示信息进行相关的依赖安装,然后继续执行知道内核配置的图形化界面出现,这里提供我在这一过程中用到的一些命令:

sudo make menuconfig
sudo apt install libncurses-dev
sudo apt install flex
sudo apt install bison build-essential

build-essential里面包含了很多开发必要的软件包,很全,很方便。如g++和其相关依赖库。

  1. 内核配置图形化界面
    在这里插入图片描述
    如图,若没有特殊需求可以直接exit-->save,当前内核的配置会保存在当前目录下的.config文件当中,然后进行下一步操作。

注:*代表编译到内核当中,M表示作为内核的模块。可使用shift+?查看帮助。
选择什么根据目标系统的特性决定,一般来说,嵌入式系统一般会使内核越小越好,因为资源本身就有限,内核小会相对稳定,启动速度也会相对快一些。

  1. 执行指令make,若提示缺少依赖,执行如下命令:
sudo apt install libssl-dev
  1. 执行如下命令:
sudo make -j4

此处使用sudo是为了防止编译时权限不足,而参数-j4则表示在多核cpu上并行多线程处理,适当使用可以有效提升编译速度!我周边大部分人在这一阶段用时三小时左右,加上-j4这一参数后编译内核耗时一个半小时。

  1. 编译完成后,执行如下命令:
sudo make modules_install
sudo make install

在这里插入图片描述
可以看到,grub引导也自动更新了,真的很方便很简单!

如果遇到如下提示:
I: The initramfs will attempt to resume from /dev/sda5
I: (UUID=423e90ce-b29e-4edd-be81-d5273deb4ed6)
I: Set the RESUME variable to override this.
解决方案如下:

执行命令:

sudo gedit /etc/initramfs-tools/conf.d/resume

然后添加如下内容:
RESUME=UUID=提示的UUID
执行下述命令后即可解决。

sudo update-initramfs -u -k all

内核编译部分到这里就结束了,验证一下是否成功:

3.4 测试验证

在这里插入图片描述
在这里插入图片描述
可以看到,无论哪种方式下查看内核版本,都是重新编译后的新版本kernel了!
再看看自定义系统调用是否成功:
在这里插入图片描述
在这里插入图片描述
OK,自定义系统调用也成功执行!完美!

至此,大功告成!希望能给大家提供到一定帮助~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章