linux编译内核模块
内核下载地址
https://www.kernel.org/
官网链接:
HTTP https://www.kernel.org/pub/
GIT https://git.kernel.org/
官网下载经常速度太慢,无法下载,提供另一个链接:
http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/
以下来自:
https://www.cnblogs.com/tsruixi/p/10777242.html
实验一:Linux内核编译及添加系统调用(HDU)
花了一上午的时间来写这个,良心制作,发现自己刚学的时候没有找到很详细的,就是泛泛的说了下细节地方也没有,于是自己写了这个,有点长,如果你认真的看完了,也应该是懂了。
一、前期准备工作
- 需要准备虚拟机上安装Ubuntu,笔者安装的是Ubuntu18.04,安装的教程自行百度解决,教程很多。有几点需要提一下,就是内存分配至少60G,核分配4个最好,为了在编译的时候别崩溃。
建议去熟悉一下Linux下面的文件目录结构,根目录下每个目录一般会存放什么样的文件
- ,然后常见命令操作也要熟悉一下。
- 下载Linux内核地址,自行选择版本,建议选择4.xx版本,因为版本高出错的概率也大。
下载好了之后,会放在自己的Ubuntu中的Downloads目录下,同时是一个压缩文件,到时候需要解压到放内核目录文件下。首先进入到该Downloads文件目录下,查看是否下载好了。
- 下载Linux内核地址,自行选择版本,建议选择4.xx版本,因为版本高出错的概率也大。
下载好了之后,会放在自己的Ubuntu中的Downloads目录下,同时是一个压缩文件,到时候需要解压到放内核目录文件下。首先进入到该Downloads文件目录下,查看是否下载好了。
$cd ~/Downloads
$ls
linux-4.19.25.tar.xz
之后开始解压上面的那个压缩文件到存放内核的地方,就是Linux系统的/usr/src目录下,此目录用来存放内核源码的。从上图也可以了解到。
cd ~/Downloads
tar xvJf linux-4.19.25.tar.xz -C /usr/src
进入/usr/src目录查看是否有,如果有就可以开始后续工作了。
二、实验要求和内容
1. 内容要求:
(1)添加一个系统调用,实现对指定进程的nice值的修改或读取功能,并返回进程最新的nice值及优先级。建议调用原型是int mysetniec(pid_t pid, int flag, int nicevalue, void_user* prio, void_user* nice);
参数含义:
pid:进程ID
flag:若为0,则表示读取nice的值;若为1,则表示修改nice的值。
nicevalue:为指定的进程设置新的nice。
prio,nice:指向进程的优先级和nice值。
返回值:系统调用成功时返回0;失败时返回错误码EFAULT。
(2)写一个简单的应用程序测试(1)中添加的系统调用。
(3)若系统调用了Linux的内核函数,要求深入阅读相关的源码。
2. Linux系统调用的基本概念
实质是指调用内核函数,于内核态中运行,Linux中的用户通过执行一条访管指令“int $0x80”来调用系统调用,该指令会产生一个访管中断,从而让系统暂停当前的进程执行,而转去执行系统调用处理程序。通过用户态传入的系统调用号从系统调用表中找到相应的服务例程的入口并执行,完成后返回。
(1)系统调用号与系统调用表:Linux内核中设置了一张系统调用表,用于关联系统调用号及其相对应的服务例程入口地址,定义在./arch/x86/entry/syscalls/syscall_64.tbl文件中,每个系统调用占一个表项,一旦分配好就不可以有任何变更。
(2)系统调用服务例程:每个系统调用都对应一个内核服务例程来实现系统调用的功能,其命名的格式都是以"sys_开头。其代码通常放在./kernel/sys.c中,服务例程的原型声明则是放在./include/linux/syscall.h中。如sys_open,通常格式是asmlinkage long sys_open(int flag......)。其中的amslinkage是一个必需的限定词,用于通知编译器从堆栈中提取函数的参数,而不是从寄存器中。
在sys.c中编程时,格式是SYSCALL_DEFINE5(mysetnice, pid_t, pid, int, flag, int, nicevalue, void __user *, prio, void __user *, nice)
N=5代表参数的个数。
(3)系统调用参数传递:在X86中,Linux通过6个寄存器来传入参数,其中一个eax是传递系统调用号,后面的5个传递参数。
(4)系统调用参数验证
三、开始实验
1. 切换到root权限下,防止权限不够,导致出错。
$ sudo passwd root
[sudo] password for leslie:
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
$ su root
Password:
(1)首先,你安装Linux系统时,它会让你设置一个你的用户名和用户密码,在这里我设置的用户名是leslie,即绿色字体leslie@tp50的前半部分,后半部分tp50是我的主机名。
sudo放在命令首,意思是当前指令以管理员权限运行。
(2)passwd是一条命令,用来修改用户密码,参数root是超级用户名,拥有系统最高的权限。passwd root的意思是修改超级用户的密码,在创建Ubuntu时,默认超级用户是没有密码的(也可能是一个随机数之类的我不记得了),用这条命令重新设定一个密码。
(3)su是一条命令,用来切换当前用户,在第一章你会认识到,Linux是一个多用户多任务的操作系统。参数root是用户名,指示切换到的用户,在这里su root意为切换到root用户,当参数缺省时,默认切换到超级用户。
(4)你会发现,它在提示输入密码时,虽然键盘已经输入了密码,但是终端没有任何响应,不要担心,这正是Unix和Linux的特点,为了确保安全,在输入密码时不显示输入的内容,在输入密码后,直接按下回车就好了。
2. 分配系统调用号,修改系统调用表
(1)查看系统调用表,并修改
gedit /usr/src/linux-4.19.25/arch/x86/entry/syscalls/syscall_64.tbl
你只需要将linux-4.19.25换成你自己下载好的版本即可。
你会看见这个格式
应用二进制接口分为三种:64、x32和common,即三种不同的调用约定,这里不需考虑太多,三种任意选择一种即可,按照上述格式编写新的系统调用表表项如下:
335 64 first_compile __x64_sys_first_compile
编译的时候发现错误,无法找到,
修改成 sys_first_compile 再测试
实际为:
(2)声明系统调用服务例程
查看系统调用头文件
$cd /usr/src/linux-4.19.34(换成自己的版本即可)/kernel
vim sys.c
函数说明:
这一步与上一步的关系,就是C语言中头文件与实现文件的关系,上一步我们对函数进行了声明,这里给函数一个具体的实现。
首先要明确,我们要实现一个什么样的功能,根据内容要求可知,这个系统调用需要具备对指定进程的nice值的修改及读取的功能,同时返回进程最新的nice值及优先级prio。
把功能分拆成一个一个小块,我们需要做到的有以下几点:
根据进程号pid找到相应的进程控制块PCB(因为进程控制块中记录了用于描述进程情况及控制进程运行所需要的全部信息,nice值和优先级正是其中的一部分);
根据PCB读取它的nice值和优先级prio;
根据PCB对相应进程的nice值进行修改;
将得到的nice值和优先级prio进行返回。
SYSCALL_DEFINE5(first_compile, pid_t, pid, int, flag, int, nicevalue, void __user *, prio, void __user *, nice)
{
int cur_prio, cur_nice;
struct pid *ppid;
struct task_struct *pcb;
ppid = find_get_pid(pid);
pcb = pid_task(ppid, PIDTYPE_PID);
if (flag == 1)
{
set_user_nice(pcb, nicevalue);
}
else if (flag != 0)
{
return EFAULT;
}
cur_prio = task_prio(pcb);
cur_nice = task_nice(pcb);
copy_to_user(prio, &cur_prio, sizeof(cur_prio));
copy_to_user(nice, &cur_nice, sizeof(cur_nice));
return 0;
}
(4)开始编译内核
首先,用下面这条命令查漏补缺,很有用处,用来它,我编译是一次通过的,没有遇见什么其他麻烦。
sudo apt-get install libncurses5-dev make openssl libssl-dev bison flex
make menuconfig
sudo make -j4 2> error.log
-j4表示使用四线程进行编译,这个过程大概持续一个小时,后面的重定向将错误信息输出到了error.log这个文件里面,方便我们之后进行错误排查,不至于一两个小时坐在电脑面前盯着信息输出生怕出现一个错误而自己错过了,之后修改只能靠两眼排查,相信我,那不是一种好的体验。
开始等待吧,结束后就可以安装内核了
(5)安装内核
此时还是在你原来的目录路径下
安装模块:
sudo make modules_install
使用这一行命令进行模块的安装,模块的安装持续时间大概在十几分钟左右,视你分配的资源多寡这个时间会适当地增加或减少。
结束后
安装内核:
sudo make install
test.c
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
#define _SYSCALL_MYSETNICE_ 335
#define EFALUT 14
int main()
{
int pid, flag, nicevalue;
int prev_prio, prev_nice, cur_prio, cur_nice;
int result;
printf("Please input variable(pid, flag, nicevalue): ");
scanf("%d%d%d", &pid, &flag, &nicevalue);
result = syscall(_SYSCALL_MYSETNICE_, pid, 0, nicevalue, &prev_prio,
&prev_nice);
if (result == EFALUT)
{
printf("ERROR!");
return 1;
}
if (flag == 1)
{
syscall(_SYSCALL_MYSETNICE_, pid, 1, nicevalue, &cur_prio, &cur_nice);
printf("Original priority is: [%d], original nice is [%d]\n", prev_prio,
prev_nice);
printf("Current priority is : [%d], current nice is [%d]\n", cur_prio,
cur_nice);
}
else if (flag == 0)
{
printf("Current priority is : [%d], current nice is [%d]\n", prev_prio,
prev_nice);
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
下载历史版本:
https://juejin.cn/post/6844903940023140360
打开官方下载链接 The Linux Kernel Archives 如下图所示:
点击打开 HTTP 的链接,比如这里我要下载 4.4.192 的版本,那么依次点击 linux->kernel->v4.x 如下图所示:
要下载的包就在这个界面,但是这个界面有点长,刚开始我以为没有。得继续往下一直拉就可以找到了,如下图:
ubuntu 内核版本下载:
不是标准的linux kernel
1 2 | $ sudo apt- get install git $ git clone git: //kernel.ubuntu.com/ubuntu/ubuntu-$(lsb_release --codename | cut -f2).git |
4.4.0-116-generic
来自:
https://www.ktanx.com/blog/p/1126
在Debian上安装完整的内核源码
在下载内核源码之前,先安装dpkg-dev,其中包含你在Debian上生成源代码时需要的开发工具套件。不仅如此,dpkg-dev中还包含在用来解压Debian源码包并自动打补丁的工具dpgk-source。
1 | $ sudo apt- get install dpkg-dev |
然后,运行以下命令下载完整的内核源码。
1 | $ apt- get source linux-image-$(uname -r) |
伴随着完整内核源码(linux_X.X.XX.orig.tar.xz)的还有一些可用的内核补丁(linux_X.X.X+XXX.debian.tar.xz)和源码控制文件(linux_XXXX.dsc),这些都将被下载并存储到当前目录。在.dsc文件中会指出如何给内核源码打补丁。
当下载完成,以上的命令将会自动调用工具dpkg-source将下载的内核源码解压到当前的目录中,与此同时根据.dsc文件来下补丁。
最终完整的内核源码树将会以”linux-X.X.XX”的形式呈现在当前目录中。
在Ubuntu上安装完整内核源码
如果你想安装完整内核源码的话,以上在Debian上的那一套做法在Ubuntu上仍然奏效。
在Ubuntu上还有另一套方法安装完整内核源码。事实上,你可以查一下由Canonical为Ubuntu不同发行版维护的内核源码树。
1 2 | $ sudo apt- get install git $ git clone git: //kernel.ubuntu.com/ubuntu/ubuntu-$(lsb_release --codename | cut -f2).git |
举个例子,如果你使用的是Ubuntu 14.04,以上的命令将会查看Git的”ubuntu-trusty”仓库中的代码。
一旦在你对Git仓库的查询结束后,使用以下的命令来安装用来访问生成内核源码树所需依赖的重要开发包。
1 | $ sudo apt- get build-dep linux-image-$(uname -r) |
参考:
https://www.cnblogs.com/tsruixi/p/10777242.html
https://richardweiyang-2.gitbook.io/kernel-exploring/00_index/01_build_your_first_kernel
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?