在想要替换原有系统内核或者需要在原来的系统中添加一些系统调用的时候就会涉及到Linux内核的编译。但是内核编译虽然步骤简单,但是需要注意的东西还是太多了。首先一点就是由于Linux的开源性导致的版本问题,并不是所有的内核都是可以编译并安装到当前系统的。其次编译过程中所需要做的一些个性化选择,当然这需要对内核了解的比较透彻,对系统各个模块也比较熟悉的时候可以定制化编译自己的内核。最后就是一些细节,需要在编译试验中不断的学习啦。
这篇博文就算是对自己编译了好几遍内核痛苦过程的一个总结和记录。编译的初衷就是在内核中添加一个简单的四则运算的系统调用,然后在用户程序中调用这个系统调用。需求如此简单,但是对于一个小白而言还是走了很多弯路。

首先说一下最重要的系统和内核版本问题:
编译的是Ubuntu的64位版本,至于是用14LTS或者12LTS无所谓,关键是要注意系统位数。因为32位和64位添加系统调用修改的内核文件是不一样的,所以这里仅仅针对64位版本而言。原来的内核是2.6.32.38,在官网下载内核版本是2.6.32.65 。现在的目标就是先修改 2.6.32.65内核的kernel文件和相关文件,然后将其编译安装替换原来的 2.6.32.38内核。

编译过程中还是使用虚拟机比较好,原因就不用说了

步骤如下:

添加系统调用

添加系统调用一共需要修改如下的三个内核文件:
1. /kernel/sys.c :用于添加系统调用函数

SYSCALL_DEFINE4(my_oper, int *, result, int, num1, int, num2, char *, op){int errno = 3; // 自定义的错误码,返回3代表操作成功,返回-3代表操作失败int cur_result = 0;char cur_op ;// 由于用户空间和系统空间并不相同// 所以用户空间的指针在系统空间并不能用// 因此要使用另外的系统调用copy_from_user()copy_from_user(&cur_op, op, 1); switch(cur_op){case '+':cur_result = num1 + num2;break;case '-':cur_result = num1 - num2;break;case '*':cur_result = num1 * num2;break;case '/':if(num2 == 0){errno = -3;cur_result = 0;}elsecur_result = num1 / num2;break;}copy_to_user(result, &cur_result, sizeof(cur_result));return errno;}

首先可以先看一下系统调用函数命名规范

其次,该函数需要注意的就是用户空间指针和系统空间指针的区别,平时自己调用自定义函数时,指针都是在用户空间中,所以不会出错。然而现在将用户空间的指针拿到了系统空间中去,就相当于是一个指向随机地址的指针,当然会出错。就好比二次元中的东西拿到现实世界的时候并不好用,通常还会出错。
最后的结果也是需要将其从系统空间转到用户空间。

  1. /arch/x86/kernel/syscall_table_32.S : 用于在系统函数表添加函数表项。是按顺序递增的,根据自己系统的实际数目即可

这里是第337个

  1. /arch/x86/include/asm/unistd_64.h : 添加系统调用号(就是第二步中添加的函数在函数表项中对应的编号)。该文件对应有两个,一个是unistd_64.h,一个是unistd_32.h,分别针对于64位和32位系统的系统调用号。

将上述的三个文件修改完成之后就可以对内核进行编译了,内核编译的资料比较多,鸟哥的书上也有专门讲过编译过程。以为本身自己对内核了解也不是很透彻,所使用的是傻瓜式的编译方式。
之所以说是傻瓜式的,是因为编译选项使用的是系统原有的默认配置信息

两种使用默认配置进行编译的方法:

  1. 可以将/boot下的config拷贝到源码根目录,命名为.config,以使用针对于本机的配置进行编译
  2. 也可以直接执行命令make menuconfig ,该命令直接根据本机的实际情况生成.config文件,自行编译不需要用户去设置。

编译添加系统调用后的内核

编译过程如下:
1. su root 切换到root权限
2. 执行make
3. 执行make modules 编译模块
4. 执行make modules-install
5. 执行make install 安装新内核

修改启动项

编译完成之后需要修改内核的启动项信息(因为此处编译之后安装将原有内核替换掉了,所以默认是进入新内核,所以此处修改启动信息,保证自己可以选择进入哪个内核),确定系统启动的时候进入的是哪个版本的内核:

修改grub文件/etc/default/grub;
注释掉如下语句:(在前面添加’#’即可)
GRUB_HIDDEN_TIMEOUT=0
注释掉之后在系统重启的时候可以选择进入的内核

由于 /boot/grub/grub.cfg文件是自动生成的,通过修改该文件选择不同的内核进行启动时无法实现的

更新启动文件:
执行update-grub就可以更新grub.cfg文件

重启进入新内核:
reboot 即可

使用 uname –a 就可以查看自己当前使用的内核是新的还是旧的

使用自己添加的系统调用

在用户空间调用自己添加的系统调用

#include <unistd.h>#include <sys/syscall.h>#define __NR_my_oper 337syscall(__NR_my_oper, result, num1, num2, op)

其中337 是自己添加的系统调用的调用号,syscall()是调用系统调用的方式,书上也会讲使用_syscallx宏来实现调用,但是2.6.20之后的内核调用并没有成功,所以就使用syscall的方式,顺利达到了目标。

【Linux】Linux添加系统调用以及内核编译过程相关推荐

  1. :linux内核编译过程的最终总结版

    参考了linuxsir和水母的linux版的精华区,本人不保留任何版权. 经过归纳整理,看看上面的就可以了,包括补丁如何打.具体的一些选项可以往下看,一些一看就懂的白痴选项,并没有选进来,因此适合对电 ...

  2. [转]Linux 2.6.19.x 内核编译配置选项简介

    Linux 2.6.19.x 内核编译配置选项简介 作者:金步国,转载地址:http://lamp.linux.gov.cn/Linux/kernel_options.html 版权声明 本文作者是一 ...

  3. Linux 2.6.19.x 内核编译配置选项简介(内核裁剪)

    Linux 2.6.19.x 内核编译配置选项简介 Code maturity level options 代码成熟度选项 Prompt for development and/or incomple ...

  4. [Linux]Linux 2.6.19.x 内核编译配置选项简介

    Linux 2.6.19.x 内核编译配置选项简介 Code maturity level options 代码成熟度选项 Prompt for development and/or incomple ...

  5. (转载) Linux 2.6.19.x 内核编译配置选项简介

    Linux 2.6.19.x 内核编译配置选项简介 作者:金步国 版权声明 本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布.任何人都可以自由使用.转载.复制和再分发, ...

  6. Linux 2.6.19.x 内核编译配置选项简介(转)

    Linux 2.6.19.x 内核编译配置选项简介 作者:金步国 版权声明 本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布.任何人都可以自由使用.转载.复制和再分发, ...

  7. 6选择内核启动项_Linux 2.6内核编译过程

    内核编译过程 Linux 2.6内核从配置,到编译,再到安装的命令非常简单,只要按顺序执行下面几个命令就可完成: 1.内核配置:make menuconfig 2.内核编译:make 3.安装模块:m ...

  8. 2.龙芯2k1000 linux3.10内核编译过程

    龙芯2k1000 linux3.10内核编译过程 文章目录 龙芯2k1000 linux3.10内核编译过程 (一).在Ubuntu环境下载并配置交叉编译链 (二).下载linux3.10内核源码 ( ...

  9. Linux 系统调用(二)——使用内核模块添加系统调用(无需编译内核)

    本文将介绍Linux使用内核模块添加系统调用的方法(无需编译内核),思路就是修改映射在内存中的系统调用表,把一个空闲的系统调用表项指向自己写的模块中的函数,如果是已使用的表项,甚至可以实现系统调用劫持 ...

最新文章

  1. matlab中libsvm 3.11,libsvm-3.11(matlab)
  2. BI工具和数据中台有什么区别?数据中台初探
  3. Java并发编程—notify和notifyAll有什么区别?
  4. php依赖注入解决什么问题,php – 了解依赖注入的问题
  5. ChaiNext:ETH底部试探后反弹,测试1500关口
  6. phpMyAdmin登录时指定服务器ip和端口的方法
  7. Q96:PT(1.2.3):圆柱2D方格纹理(Cylinder 2D Checker)
  8. python3 socket sendall_全网最详细python中socket套接字send与sendall的区别
  9. 用递归实现求一个迷宫是否有通路
  10. php保存上传的音频文件在哪里,php 视频、音频和图片文件上传,该如何解决
  11. 青花瓷(charles)的基本使用和注意事项
  12. java 调用阿里云中通快递查询示例
  13. python -字典生成器
  14. 计算机到点就有音乐怎么清除缓存垃圾,如何自动清理网易音乐的缓存
  15. U3d引擎与资源管理
  16. Transform 3.1 用户手册(SPSS 的通用数据转换程序)
  17. 利用高德api实现自定义区域下钻
  18. 莫凡的python_周莫凡python
  19. 没想到吧!没签劳动合同,能不能拿到双倍工资赔偿?今天统一回复~【文末送书】...
  20. 三、JumpServer堡垒机用户使用手册

热门文章

  1. mysql索引查询 with_mysql的select语句总结与索引使用
  2. 5.QML动画——分组动画
  3. vue插槽样式_Vue为什么要有插槽
  4. Android Gradle 构建工具(Android Gradle Build Tools)是什么?
  5. Redis系列-远程连接redis并给redis加锁
  6. HDU 1028 HDU Ignatius and the Princess III
  7. 使用varnish + nginx + lua搭建网站的降级系统
  8. Javascript获取当月的天数
  9. vue中使用MD5加密
  10. [NOI2017]游戏(2-SAT)