内核版本升级和添加Linux系统调用

浏览:
字体:
发布时间:2013-12-20 16:18:40
来源:
一、 系统调用简介

所谓系统调用,就是内核提供的、功能十分强大的一系列的函数。这些系统调用是在内核中实现的,再通过一定的方式把系统调用给用户,一般都通过门陷入(gate trap)实现。系统调用就是用户空间应用程序和内核提供的服务之间的一个接口。由于服务是在内核中提供的,因此无法执行直接调用;相反,您必须使用一个进程来跨越用户空间与内核之间的界限。在特定架构中实现此功能的方法会有所不同。

实现系统调用的方法有多种,最常用的是一个特殊的中断,即陷入(int指令),其中断向量号是$0x80。因此,系统调用的处理过程也就是int $0x80的处理过程。当执行到指令int $0x80时,处理器会将堆栈切换到当前进程的系统堆栈,并在栈顶自动压入SS、ESP、EFLAGS、CS、EIP,而后跳转到system_call。

程序system_call的处理流程如下:

(1)将EAX中的系统调用号压入栈顶。

(2)将其余的寄存器压入栈顶,形成一个pt_regs结构。值得注意的是服务函数都通过堆栈接收参数,而处于栈顶位置的寄存器(EBX、ECX、EDX、ESI、EDI、EBP)恰好是传递给服务函数的参数。

(3)检查EAX中的系统调用号是否越界。

(4)根据EAX中的系统调用号查系统调用表sys_call_table,获得该调用号对应的服务函数,调用该函数完成系统调用的服务处理工作。系统调用服务函数通过堆栈接收参数,参数的个数是预先约定好的。

(5)当服务函数返回时,用EAX中的返回值替换栈顶的ax。

(6)关闭中断(CLI)。

(7)善后处理:1)根据当前进程的设置完成必要的审计工作;2)如果当前进程需要调度,则调度它;3)如果当前进程有待处理的信号,则处理它;4)弹出栈顶,恢复各段寄存器、各通用寄存器及EIP、CS、EFLAGS、ESP、SS等寄存器的值,返回用户态,继续执行int $0x80之后的指令。此时,EAX中值是栈顶的ax,及系统调用的返回值。

二、 实验环境

Windows 7(2G内存)中安装了VMware 9.0.0虚拟机;

虚拟机中安装了Ubuntu 12.04(LTS)版(512M内存)。

三、 实验内容

(1) linux内核版本升级

(2) 添加linux系统调用

四、 实验步骤

1、获取当前内核版本:

通过命令 uname –a获取当前内核版本,主要便于后来对比观察内核版本升级是否成功。可以看到我当前的版本为linux-3.2.0-29

2、下载内核源码:

1)到网站https://www.kernel.org/ 下载新的内核源码,(如果单单只做添加系统调用的实验的话,也可以使用系统中带有的源代码,在/usr/src/中)。本次实验我下载的是比较新一点的内核版本linux-3.10。
2)下载之后,是一个压缩文件,叫做linux-3.10.tar.xz,这里我们把它移动到/usr/src/目录下,(其实这里的移动不是必须的,只是网上有好多教程都做了移动)。在终端(shell)中进入下载目录后,执行命令sudo mv linux-3.10.tar.xz /usr/src/
输入密码,移动成功后,解压文件,进入/usr/src/后执行命令:
sudo tar –xvf linux-3.10.tar.xz,解压出文件夹linux-3.10。(
z:通过gzip支持压缩或解压缩。还有其他的压缩或解压缩方式,比如j表示bzip2的方式。 x:解压缩。c是压缩。 v:在压缩或解压缩过程中显示正在处理的文件名 f:f后面必须跟上要处理的文件名。

3、下载并安装用于源码配置的工具,这一部分,可以参考一下ubuntu论坛的文章,http://forum.ubuntu.org.cn/viewtopic.php?t=134404,不过他编译的内核为2.6.25,我们这里只是将命令粘出来,实际上就是下载了几个包,在我们编译配置时可能会用到。
sudo apt-get install build-essential kernel-package libncurses5-dev
4、修改源码,我们的目的是添加一个新的系统调用。(提醒一下,修改源码需要较高的权限,可以使用命令sudo gedit 文件名,或者su gedit 文件名)
1)/usr/src/linux-3.10/kernel/sys.c
添加头文件  #include <linux/linkage.h>
文末添加自定义的系统调用函数:
/
2)/usr/src/linux-3.10/arch/x86/syscalls/syscall_32.tbl
(如果你的虚拟机是64位的,则需修改syscall_64.tbl)
在系统调用向量表里添加自定义的系统调用号(这个可以适当选取一个没有用到的号):
/
其中356是我为hello这一系统调用定义的功能号。
3)/usr/src/linux-3.10/arch/x86/include/asm/syscalls.h
在适当的位置添加系统调用函数声明:
/
5、内核编译
(这是一个漫长的过程,由于我是在虚拟机中运行的,编译一次至少用4个小时)
1)如果不是第一次进行内核编译,需要对之前的设置进行清理,清理以前编译留下的临时文件;如果是刚刚解开的源码包,不用执行此步:sudo make mrproper
2)内核配置http://blog.csdn.net/xuyuefei1988/article/details/8635539
sudo make menuconfig(基于文本选单的配置界面,字符终端下推荐使用)
sudo make xconfig(基于图形窗口模式的配置界面,Xwindow下推荐使用)
sudo make oldconfig(如果只想在原来内核配置的基础上修改一些小地方,会省去不少麻烦)
这里为了方便我们直接将内核配置默认为原来内核的配置,执行以下命令即可:
sudo make olddefconfig
3)编译内核和模块
(依次执行“make”、“make modules”、“make modules_install”、“make install”,如果前面的配置没有问题的话,耐心等待一段时间就可以得到编译好的内核和模块了。)在Ubuntu下,安装kernel-package这个包之后,就可以使用make-kpkg来简化编译流程了。
sudo make-kpkg clean  (清理)
sudo make-kpkg  --initrd  --append-to-version=wrm128 kernel-image kernel-headers(在版本后追加字符串wrm128,生成kernel-image和kernel-headers文件)。
编译成功后:
/ 4)安装内核
编译完成后,在/usr/src/中会看到生成两个deb文件。执行以下命令进行安装:
sudo dpkg -i linux-image-3.10.0wrm128_3.10.0wrm128-10.00.Custom_i386.deb
linux-headers-3.10.0wrm128_3.10.0wrm128-10.00.Custom_i386.deb
(这两个文件名有点儿长,敲命令时可以用tab键补全)。这两个文件解压安装成功之后,在usr/src/目录下会生成文件linux-headers-3.10.0wrm128,也就是替换成功的新内核。
5)重启系统
执行命令:sudo reboot 重启系统。如果一切顺利的话,应该能够重启成功。
/
键入命令:uname  -a,查看一下现在的内核版本:
/
可以看到现在的内核版本已经变为3.10.0wrm128,说明内核升级及编译已经成功喽!
6、测试系统调用
1)在主文件目录(/home)下创建文件夹:mkdir test
进入/home/test/目录下,创建文件testHello.c:gedit testHello.c
编写测试代码:
/
在我的系统调用函数中有一个char *的字符串参数,故在调用时不仅要将系统调用号356传入,还要将char * 的字符串传入。

syscall是内核提供为用户程序的一个函数,如果不使用syscall函数,也可以使用宏定义,但是在2.6.20以后的版本里,没有宏定义,需要自己从其他版本里复制过来添加。

2)编译,运行
进入/home/test/目录,执行命令:gcc  -testHello.c  -o  testHello
编译成功后,执行命令:./testHello
/
3)查看内核日志
查看系统调用在内核空间的运行情况,执行命令:dmesg
/
可以看到参数”wrm”已传入,系统调用函数成功执行!
OK,终于大功告成!
小结:第一次因为电耗尽了,没有带电源,然后4个小时就废了;第二次(4个多小时)内核升级成功了而系统调用失败了,查了半天,才发现自己太蠢,follow网上教程将系统调用号定义在了syscall_64.tbl中,而忽略了自己的系统是32位的;第三次编译了1个多小时时报错了:arch/x86/built-in.o:(.rodata+0x610): undefined reference to `sys_hello' make: *** [vmlinux] Error 1 网搜有类似错误却没有答案,只好一个文件一个文件查看,看哪里出了问题,致使找不到sys_hello,最后发现syscalls.h中好像找不到我添加的系统调用函数的声明。只好手动添加,然后重新编译。。。第四次,编译了至少5个小时,从晚上8点到1点多,终于OK!佩服自己竟然没有中途放弃。。。
最终编译成功是失败三次的结果,实验证明在虚拟机中编译内核真的是一个无比漫长的过程。 不同的操作系统及内核版本的操作流程可能会有所不同,不能完全参照网上的教程,这个需要试验和摸索。 经过几次失败之后,对内核编译和添加系统调用一定会有更深的理解!
>更多相关文章
24小时热门资讯
24小时回复排行
资讯 | QQ | 安全 | 编程 | 数据库 | 系统 | 网络 | 考试 | 站长 | 关于东联 | 安全雇佣 | 搞笑视频大全 | 微信学院 | 视频课程 |
关于我们 | 联系我们 | 广告服务 | 免责申明 | 作品发布 | 网站地图 | 官方微博 | 技术培训
Copyright © 2007 - 2024 Vm888.Com. All Rights Reserved
粤公网安备 44060402001498号 粤ICP备19097316号 请遵循相关法律法规
');})();