Linux内核中增加一个系统调用

合集下载

编译内核-新增Linux系统调用过程

编译内核-新增Linux系统调用过程

一、题目:新增Linux系统调用(1)需要重新编译Linux内核(2)增加一个Linux的系统调用(3)写一个用户程序进行调用测试。

系统调用实现的功能:计算一个数字的三次方,并打印出来。

二、版本:编译版本:Win10上虚拟机(Virtual Box) Ubuntu(64bit)15.04系统原内核版本:3.19.0编译的新内核源码版本:3.2.75不同内核版本,32位和64位文件位置以及文件名可能有所不同。

添加系统调用时要根据自己的版本的文件位置和文件名修改相应的三个文件。

三、步骤:1.前期准备:下载内核及解压1.1下载内核:1.2打开终端获得权限然后再输入su输入刚刚设置的密码。

1.3移动文件并解压下载目录2.添加系统调用2.1添加系统调用函数在文末添加调用函数。

然后保存,关闭。

2.2 添加调用函数声明在文末#endif前添加函数声明。

然后保存关闭。

2.3添加系统调用号因为前一个系统调用号是311 所以这里我们写312将原本的#defineNR_syscalls (__NR_syscall_max+1)修改为:#defineNR_syscalls (__NR_syscall_max + 2)然后保存,关闭。

3.编译内核3.1安装基本编译器套件3.2编译3.1make mrproper清除以前配置(如果是第一次编译,不用执行此操作)3.2 make menuconfig配置内核(此处选择了默认配置)3.3 make编译内核如果电脑是双核则也可以用make–j4代替make(双核编译会更快一些)接下来就是漫长的等待过程,不过要随时注意是否编译过程中因有错误而停止。

我的电脑用了两个小时。

(也有教程里用的是make bzlmage和makemodules,make bzlmage+make modules=make)4.安装内核4.1makemodules_install4.2makeinstall4.2 reboot重启(或不使用命令直接对电脑进行重启)ﻩ重启之后在开机时候开机时候,如果是虚拟机需要同时按esc和↑键出现开机启动项(如果是真机开机一般会自动出现开机启动项),选择新建的内核版本进入。

linux实验_添加系统调用-完整版

linux实验_添加系统调用-完整版

实验一添加一个新的系统调用一、实验目的理解操作系统内核与应用程序的接口关系;加深对内核空间和用户空间的理解;学会增加新的系统调用。

二、实验内容与要求首先增加一个系统调用函数,然后连接新的系统调用,重建新的Linux内核,用新的内核启动系统,使用新的系统调用(2.4内核和2.6内核任选一个)三、实验指导(2.6版本)⑴获得源代码(本次实验的内核版本是2.6.22.5,必须是root用户)1.从教育在线上下载内核源代码到本地磁盘;保存在/usr/src目录下2.进入终端,输入命令cd /usr/src 进入/usr/src目录(可以输入ls命令会发现目录下有一个名为LINUX_2_6_22_5.TAR.BZ2的压缩文件)3.当前目录下(/usr/src)输入命令tar –xjvf LINUX_2_6_22_5.TAR.BZ2 解压缩源代码,命令执行完毕后,会出现/usr/src/linux-2.6.22.5文件夹4.修改文件夹下的3个文件第一,编辑/usr/src/linux-版本号/kernel/sys.c文件,添加函数:asmlinkage long sys_mycall(long number){printk(“call number is %d\n”,number);return number;}第二,修改/usr/src/linux-版本/include/asm-i386/unistd.h添加一行#define __NR_mycall 324 到当前的最大系统调用号之后,比如原来最大的是323,在323的这一行之后加上一行#define __NR_mycall 324修改#define NR_systemcalls 的值,改成原来的值+1,比如原来是324 改成325第三,编辑/usr/src/linux-版本/arch/i386/kernel/syscall_table.S,在文件最后加上一行:.long sys_mycall5.重新编译内核在终端输入命令,进入源代码文件夹,cd /usr/src/linux-2.6.22.5 依次执行如下命令:make mrpropermake cleanmake xconfig (自己配置内核,出现图形对话框后,直接点保存,关闭)make(耗时最长,大约20分钟)make modules_install (安装模块)以上命令执行完毕后,会在当前目录下生成一个名为System.map的文件,会在/usr/src/linux-版本号/arch/i386/boot/下生成一个bzImage文件。

编译Linux2.6内核并添加一个系统调用

编译Linux2.6内核并添加一个系统调用

1. 0 让新 内核和 旧内核 都可 以加载 的配置 的步骤 :
my. r h i 8 / o t z ma e/ o t / c /3 6 b o / l g b o a b mv. y t m. p/ o t / s e ma b o S
mv/ o t zma e/o t mln z 261 ..5 3 b / l g b b / i u - ..510 0 v
2 1 年第 4期 0 1

建 电

19 4
编 译 iu26内 并 添 加 一 个 系统调 用 Ln x . 核
张 伟 华 .王 海 英 。高 静
(河南 财经政 法 大学成 功 学院 河 南 郑 州 4 10 5 2 0)
【 摘 要 】 本 文 以实例 来详 细描 述 了从 准备 一直 到使 用新 内核 的 Lnx 。 : iu 26内核 编译过 程 , 然后介 绍 了
轻 易地 对它进 行修 改 .使 我们 能够 根据 自己的要 求 度 身 定制 一个更 高效 、 更稳 定 的 内核 。
系统调 用【 用户 进程 与 系统之 间 的接 口, 们在 2 ] 是 它 内核 中实 现 .其 主要 目的是 使得 用户 可 以使 用操 作 系 统提 供 的操作底 层设 备 的功 能 用 户 程序 肯定 要 操作
mv/ o t y tm. p/ o ' y t m. p 2 6 1 .. 5 b / se ma b oJ s e ma - .. 5 10 03 S , S mk n td/ o g n td 2.. 5 10 0 . 6.5 1 ii b r i i - 6 1 . . 5 3 i 2. 1 r mg v / o t rbgu e n ib / u / r b.o f g

操作系统实验一向LINUX内核增加一个系统调用

操作系统实验一向LINUX内核增加一个系统调用

操作系统实验一向LINUX内核增加一个系统调用一、背景介绍操作系统是计算机硬件与应用程序之间的接口,负责管理和调度计算机系统的各种资源,并提供用户与计算机系统的交互界面。

内核是操作系统的核心部分,负责管理和分配计算机系统的资源,执行各种任务。

系统调用是操作系统提供给应用程序的一种接口,可以让应用程序访问内核提供的功能,例如文件操作、进程管理、网络通信等。

在一些情况下,我们可能需要在LINUX内核中增加新的系统调用,以满足特定的需求。

本文将介绍如何向LINUX内核增加一个系统调用的具体步骤。

二、增加系统调用的步骤1.编写系统调用的具体实现代码首先,我们需要编写一个具体的系统调用的实现代码。

在LINUX内核中,系统调用的实现代码通常位于内核的/syscalls目录下。

我们可以在该目录下新建一个.c文件,编写我们自己的系统调用代码。

2.修改内核源代码3.更新系统调用表每个系统调用都在内核中有一个唯一的标识符,存储在一个叫做系统调用表的地方。

我们需要更新系统调用表,将新增的系统调用添加到表中。

这样,用户程序才能够通过系统调用号来调用新增的系统调用。

4.重新编译内核在修改完内核源代码后,我们需要重新编译内核。

这通常涉及到一些繁琐的步骤,例如配置内核选项、编译内核、安装内核等。

在重新编译内核之后,我们需要重新启动计算机,使新的内核生效。

5.修改用户程序最后,我们需要修改用户程序,以便能够调用新增的系统调用。

用户程序通常是通过C语言编写的,我们可以在用户程序的代码中添加对新增系统调用的调用代码。

三、实验结果在完成上述步骤后,我们就成功地向LINUX内核增加了一个系统调用。

用户程序可以通过系统调用调用自己新增的系统调用,从而实现特定的功能。

总结:本文介绍了向LINUX内核增加一个系统调用的具体步骤,包括编写系统调用的具体实现代码、修改内核源代码、更新系统调用表、重新编译内核和修改用户程序。

在实施这些步骤之前,我们需要对操作系统和内核的相关概念有一定的了解,并具备一定的编程能力。

添加一个系统调用

添加一个系统调用

修改Linux内核增加系统调用一,修改内核增加系统调用只修改/usr/src/linux-2.4.29/include/asm-i386/unistd.h和arch/i386/kernel/entry.S,系统调用函数一般在kernel/sys.c中,这里把增加的系统调用代码也加入这个文件中。

1.修改kernel/sys.c文件,加入自己的系统调用代码,同参考文献(见文后地址)中,asmlinkage int sys_addtotal(int numdata){int i=0,enddata=0;while(i<=numdata)enddata+=i++;return enddata;}计算从0到numdata的累加值。

asmlinkage表示通过堆栈递参数。

2.然后把sys_addtotal(int )的入口地址添加到sys_call_table表中。

该表依次存储所有系统调用的入口地址。

修改前为:.long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address 这是第258个系统调用* /.rept NR_syscalls-(.-sys_call_table)/4.long SYMBOL_NAME(sys_ni_syscall)修改后:.long SYMBOL_NAME(sys_ni_syscall) /* sys_set_tid_address * /.long SYMBOL_NAME(sys_addtotal) /*这是增加的第259个系统调用*/.rept NR_syscalls-(.-sys_call_table)/4-1 /*这里重复次数减少1*/ .long SYMBOL_NAME(sys_ni_syscall)3. 把增加的sys_call_table 表项所对应的向量,在include/asm-i386/unistd.h 中进行必要申明,以供用户进程和其他系统进程查询或调用:#define __NR_exit_group 252#define __NR_addtotal 259 /*这是增加的第259个系统调用*/然后编译内核make bzImage,并用生成的新内核启动系统。

增加系统调用实验报告(3篇)

增加系统调用实验报告(3篇)

第1篇一、实验目的1. 了解系统调用的基本概念和作用。

2. 掌握在Linux内核中增加系统调用的方法。

3. 熟悉系统调用在用户空间和内核空间之间的交互过程。

4. 提高编程能力和系统理解能力。

二、实验环境1. 操作系统:Linux2. 编译器:gcc3. 开发工具:内核源代码、makefile三、实验原理系统调用是操作系统提供的一种服务,允许用户空间程序请求内核空间的服务。

在Linux内核中,系统调用通过系统调用表来实现。

增加系统调用需要修改内核源代码,并重新编译内核。

四、实验步骤1. 创建系统调用函数首先,我们需要创建一个系统调用函数,该函数将实现一个简单的功能,例如打印一条消息。

以下是一个简单的系统调用函数示例:```cinclude <linux/module.h>include <linux/kernel.h>include <linux/init.h>static int __init hello_init(void) {printk(KERN_INFO "Hello, World!\n");return 0;}static void __exit hello_exit(void) {printk(KERN_INFO "Goodbye, World!\n");}module_init(hello_init);module_exit(hello_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Your Name");MODULE_DESCRIPTION("A simple system call module");MODULE_VERSION("0.1");```2. 修改系统调用表接下来,我们需要修改内核源代码中的系统调用表,以注册我们创建的系统调用。

两种方法添加系统调用

两种方法添加系统调用

两种⽅法添加系统调⽤通过修改内核源代码添加系统调⽤通过以上分析linux系统调⽤的过程,将⾃⼰的系统调⽤加到内核中就是⼀件容易的事情。

下⾯介绍⼀个实际的系统调⽤,并把它加到内核中去。

要增加的系统调⽤是:inttestsyscall(),其功能是在控制终端屏幕上显⽰hello world,执⾏成功后返回0。

1编写inttestsyscall()系统调⽤编写⼀个系统调⽤意味着要给内核增加1个函数,将新函数放⼊⽂件kernel/sys.c中。

新函数代码如下:asmlingkage sys_testsyscall(){ console_print("hello world ");return 0;}2连接新的系统调⽤编写了新的系统调⽤过程后,下⼀项任务是使内核的其余部分知道这⼀程序的存在,然后重建包含新的系统调⽤的内核。

为了把新的函数连接到已有的内核中去,需要编辑2个⽂件:1).inculde/asm/unistd.h在这个⽂件中加⼊#define_NR_testsyscall 1912).are/i386/kernel/entry.s这个⽂件⽤来对指针数组初始化,在这个⽂件中增加⼀⾏:.long SYMBOL_NAME(_sys_tsetsycall)将.rept NR_syscalls-190改为NR_SYSCALLS-191,然后重新奖励和运⾏新内核。

3).使⽤新的系统调⽤在保证的C语⾔库中没有新的系统调⽤的程序段,必须⾃⼰建⽴其代码如下#inculde_syscall0(int,testsyscall)main(){tsetsyscall();}在这⾥使⽤了_syscall0()宏指令,宏指令本⾝在程序中将扩展成名为syscall()的函数,它在main()函数内部加以调⽤。

在testsyscall()函数中,预处理程序产⽣所有必要的机器指令代码,包括⽤系统调⽤参数值加载相应的cpu寄存器,然后执⾏int 0x80中断指令。

(完整word版)Linux内核中增加一个系统调用

(完整word版)Linux内核中增加一个系统调用

选题要求:在Linux内核中增加一个系统调用,并编写对应的linux应用程序。

利用该系统调用能够遍历系统当前所有进程的任务描述符,并按进程父子关系将这些描述符所对应的进程id(PID)组织成树形结构显示。

目录一.程序的主要设计思路,实现方式 (1)1.1 添加系统调用的两种方法 (1)1.1.1编译内核法 (1)1.1.2内核模块法 (1)1.2 程序的主要设计思路 (1)1.3 环境 (2)二.程序的模块划分,及对每个模块的说明 (2)2.1 通过内核模块实现添加系统调用 (2)2.1.1修改系统调用的模块 (2)2.1.2获取sys_call_table的地址 (2)2.1.3清除内存区域的写保护 (3)2.2 编写系统调用指定自己的系统调用 (4)2.2.1内核的初始化函数 (4)2.2.2自己的系统调用服务例程 (4)2.2.3移除内核模块时,将原有的系统调用进行还原 (6)2.2.4模块注册相关 (6)2.3 编写用户态的测试程序 (6)2.4 编写Makefile文件 (7)三.所遇到的问题及解决的方法 (8)3.1 进程个数确定 (8)3.2 被更改的系统调用号的选择 (8)3.3 获取系统调用表的地址 (8)3.4 内核和用户态数据交换 (8)四.程序运行结果及使用说明 (8)4.1 将编译出来的内核模块hello.ko加载到内核中 (8)4.2通过dmesg查看输出信息是否正确 (9)4.3运行测试程序,输出树状打印结果(部分结果截图) (9)4.4卸载自定义模块 (10)五.附录 (11)5.1 内核模块程序hello.c (11)5.2 测试程序hello_test.c (14)5.3 Makefile文件 (14)一.程序的主要设计思路,实现方式1.1 添加系统调用的两种方法1.1.1编译内核法编写好源码之后以上准备工作做完之后,然后就要进行编译内核了,以下是编译内核的一个过程1.1.2内核模块法内核模块可以作为独立程序来编译的函数和数据类型的集合。

操作系统原理-实验-linux增加系统调用

操作系统原理-实验-linux增加系统调用

中国地质大学(武汉)《操作系统原理》课程实验报告数据科学与大数据技术专业班级195182学生姓名钟欢任课教师康晓军完成时间2020年3月31日实验一——实现一个linux的系统调用一、实验目的1.加深对系统调用的理解,掌握增加与调用系统调用的方法。

2.掌握内核编译方法。

二、实验思路1.增加新的系统调用:新增的系统调用名为Hello,其功能是打印输出“This is ZhongHuan ’ s system call ! wo zhong yu cheng gong le !”2.编译内核:用编译内核的方法,将其增加进内核源码并编译内核。

3.测试:在用户控件编写测试程序测试该系统调用。

三、实验步骤1.系统调用的添加在Linux中添加新的系统调用,需执行多个步骤才能添加成功:(1)第一步完成系统调用函数在内核源码目录kernel/sys.c文件中编写待添加的系统调用函数。

该函数的名称应该是新的系统调用名称前面加上sys_标志。

新加的系统调用为hello(void),在kernel/sys.c文件中添加源代码:asmlinkage long sys_hello(void){printk("This is ZhongHuan&apos;s system call! wo zhong yu cheng gong le!");return 1;}(2)第二步在系统函数表中表项添加新的系统调用后,需要让Linux内核的其余部分知晓该程序的存在。

在内核源码目录arch/x86/entry/syscalls下修改文件syscall_64.tbl。

该文件用来对sys_call_table[]数组实行原始化,数组包含指向内核中每个系统调用的指针。

在该文件中的最后一行添加自己的系统调用表项:335 64 hello sys_hello(),这样就在数组中添加了新的内核函数指针。

(3)第三步添加系统调用号在内核源码目录arch/x86/include/asm下修改头文件unistd_32.h。

LinuxOS实验一:内核编译及添加系统调用

LinuxOS实验一:内核编译及添加系统调用

LinuxOS实验⼀:内核编译及添加系统调⽤简单整理下上周做的OS的lab1,前半部分主要介绍Linux内核编译和添加系统调⽤的流程,后半部分主要简要探索⼀下添加的系统调⽤中所⽤到的内核函数的源码。

⾸先贴⼀下这次实验的要求和我的实验流程图:Linux内核编译流程实验环境我的实验环境是VMware虚拟机下的Ubuntu 16.04,使⽤uname -a命令查看了⾃⼰的内核版本是4.15.0,于是确定待编译的新内核版本是:4.16.1(这个版本应略⾼于Linux系统的内核版本)。

同时,由于在内核编译过程中会⽣成较多的临时⽂件,如果磁盘空间预留很⼩,会出现磁盘空间不⾜的错误⽽导致内核编译失败;内存太⼩则会影响编译速度。

所以,这⾥建议虚拟机的配置参数:内存2GB以上,磁盘空间40GB以上。

由于我在做内核编译之前的时候就已经安装了linux虚拟机,所以这⾥我需要先扩展磁盘内存,具体参考了以下博⽂:。

下载内核源码并解压在中找到对应版本的内核源码并下载(如上⽂所说,这⾥我选择4.16.10,请视Linux系统的具体情况⽽定):在Linux系统中切换⾄root⽤户(随后的所有步骤都应以root⽤户进⾏操作,⽆法切换的可以尝试passwd命令修改root⽤户密码),然后将压缩⽂件复制到/home或其他⽐较空闲的⽬录中,进⼊压缩⽂件所在⼦⽬录,使⽤以下命令解压:xz -d linux-4.16.10.tar.xztar -xvf linux-4.16.10.tar清楚残留的.config和.o⽂件每次完全重新编译的时候都应从这⼀步开始,为了防⽌出现错误,我们先安装所需要的对应包:apt-get install libncurses5-dev随后执⾏命令:make mrproper配置内核执⾏命令:make menuconfig,随后出现诸如以下界⾯:我们选择默认值:保存配置信息,选⽤默认的⽂件名.config,最后编译内核先安装所需的包以防编译时报错:=>安装openssl:apt-get install libssl-dev=>安装bison:apt-get install bison=>安装flex:apt-get install flex随后执⾏命令:make,强烈建议使⽤命令make -j4或make -j8来加快编译速度,这⾥第⼀次进⾏内核编译的时候需要⽐较长的时间,我的电脑⼤概跑了⼀个多⼩时。

向Linux内核增加一个系统调用

向Linux内核增加一个系统调用

操作系统实验一实验报告一、基本信息:实验题目:向Linux内核增加一个系统调用完成人姓名:金威报告日期:2016年4月24日二、实验目的通过实验,熟悉Linux操作系统的使用,掌握构建与启动Linux内核的方法;掌握用户程序如何利用系统调用与操作系统内核实现通信的方法,加深对系统调用机制的理解;进一步掌握如何向操作系统内核增加新的系统调用的方法,以扩展操作系统的功能。

三、实验内容1. Linux环境下的C或C++编译和调试工具的使用。

2. 向Linux内核增加新的系统调用,系统调用名称和功能自行定义,但必须实现如下输出功能:“My Student No. is ×××,and My Name is ×××”。

3. Linux新内核的编译、安装和配置。

4. 编写应用程序以测试新的系统调用并输出测试结果。

四、实验步骤1.第一次尝试了使用Virtual Box ,但是出了一些问题,虚拟机网连不上就换了VMware workstations ,曾试过用ubuntu-10.04.4-desktop-i386和比较老版本的内核,但是过程略繁琐,且很容易出错,就更换了Ubuntu 64 15.10 来创建虚拟机。

2.我先在windows中下载了linux-4.2的内核,然后直接拖入了虚拟机中(拖入的过程有时可能会无法进行,可以对虚拟机的Vmware Tools重新安装,或者用共享文件夹的形式拖入),拖入了桌面后,我直接进行了解压,较新版本无需cp 入/usr/src中。

3.接着进入终端,sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot 获得编译内核必需,但是这个所需下载的东西太多,有1个G左右,中间可能如果网络出现故障,出现故障中断下载后我是按它的提示输入了apt-get update更新软件环境。

操作系统项目:向Linux内核添加一个系统调用

操作系统项目:向Linux内核添加一个系统调用

操作系统项⽬:向Linux内核添加⼀个系统调⽤内容:1. 向Linux增加⼀个系统调⽤2. 撰写⼀个应⽤测试程序调⽤该系统调⽤3. 使⽤ptrace或类似的⼯具对该测试程序进⾏跟踪调环境:1.vmware workstation 15.0.02.ubuntu-18.10-desktop3.linux-4.18.14步骤:⼀.准备环境在终端操作:sudo apt-get update //更新系统源码sudo apt-get install vim //安装vimsudo apt-get install libncurses5-dev libssl-dev //下载依赖包sudo apt-get install libelf-devsudo apt-get install build-essential opensslsudo apt-get install zlibc minizipsudo apt-get install libidn11-dev libidn11sudo apt-get install flex bison⼆.构建新内核1.准备在下载解压将在官⽹下好的内核直接拉到ubuntn⾥,然后将压缩包⽤指令移到/usr/src⽬录下(过程需要root权限)。

sudo su //获取rootsudo mv 压缩包位置 /usr/src //移动⽂件cd /usr/src //切换到该⽬录下进⾏操作sudo tar -xvflinux-4.18.14.tar.gz //解压2.添加系统调⽤先将⽬录切换到解压后的内核⾥操作1. sudo vim kernel/sys.c //添加⾃⼰的函数这⾥添加了sys_helloworld2.sudo vim arch/x86/include/asm/syscalls.h //添加声明3.sudo vimarch/x86/entry/syscalls/syscall_64.tbl //添加调⽤号3.删除⽆⽤的⽂件sudo make mrpropersudo make clean4.配置sudo make menuconfig此处直接save,exit即可,⽆需修改5.编译新内核并安装A.编译sudo make -j2 //将处理机内核总数调整为4,会明显加快编译速度(-j2为开启双线程编译)B.安装sudo make modules_installsudo make install6.重启//reboot三.测试先使⽤vim写⼀个测试的cpp之后gcc编译(前提是apt-get install build-essential安装gcc/g++/gdb/make 等基本编程⼯具。

linux增加系统调用实验

linux增加系统调用实验

实验二增加系统调用实验报告一修改系统文件1.在系统调用表中添加相应表项# cd /usr/src/linux-2.4/arch/i386/kernel# vi entry.S添加.long SYMBOL_NAME(sys_pedagogictime)见图1:2. 添加系统调用号# cd /usr/src/linux-2.4/include/asm# vi unistd.h添加# define __NR_pedagogictime 259见图2:3. 在文件最后添加一个系统服务例程# cd /usr/src/linux-2.4/kernel# vi sys.c添加sys_pedagogictime见图三二.编译内核# cd /usr/src/linux-2.4# make mrproper# make xconfigBlock devices → Loopback device support 选YSCSI support → SCSI low-level drivers → BusLogic SCSI support 选YFile systems → Ext3 journallingfile system support 选YNTFS file system support 选YSave and exit# make dep# make clean# make bzImage# make modules# make modules_install从/etc/modules.conf中删除BusLogic的加载项#alias scsi_hostadapter BusLogic /* 否则make install时总报错:No module BusLogic found for kernel 2.4.22 */ # cd /usr/src/linux-2.4# make install三将新内核和System.map拷贝到/boot目录下# cp /usr/src/linux-2.4/arch/i386/boot/bzImage /boot/vmlinux-2.4.20# cp /usr/src/linux-2.4/ System.map /boot/System.map-2.4.20# cd /boot# rm –f System.map# ln –s System.map-2.4.20 System.map四修改Grub启动管理器# cd /boot/grub# vi menu.lst修改menu.lst文件,将Red Hat Linux (2.4.20-8custom)部分中的root=LABEL=/改为root=/dev/sda2修改前见图四修改后见图五五重启系统:# reboot重启后显示如图六:选择Red Hat Linux (2.4.20-8custom),回车六编辑用户空间的测试程序:.运行结果:。

关于Linux系统增加系统调用的方法

关于Linux系统增加系统调用的方法

Linux系统增加系统调用之前的一段时间就做过Linux系统的系统调用的实验,但是一直无法最终实现,这几天又重新捣鼓了一下,最终终于成功实现了在Linux中增加系统调用,在此本人使用的Linux 系统为Red Hat Linux 9.0,系统内核为linux-2.4.80的版本。

下面就讲述一下个人的实验经过。

一、系统文件修改进入Red Hat Linux 9.0后,右击桌面,打开终端,在终端中输入cd命令到内核目录下:[root@localhost root]#cd /usr/src/linux-2.4如下图所示:图1首先,进入/usr/src/linux-2.4/kernel目录,用ls查看该目录下的文件,找到其中的sys.c 文件,如下所示:图2若在kernel目录下找不到sys.c文件,说明在安装的时候没有将内核编译工具以前装上,可以导入安装光盘,双击打开进行系统工具的添加。

找到该文件后,使用命令:[root@localhost kernel]#gedit sys.c打开文件,并将要增加的系统调用写入其中,如下所示:图3图中选中部分内容即为本次本人所增加的系统调用,因为这是一次实验,所以增加的内容显得比较简单,只是调用一个foo函数,输出一个整数,在添加的内容中,有几点要特别注意:1、在sys.c中,增加的系统调用的函数名必须以“sys_”开头2、输出语句应为printk()而不是printf(),这和之前所认识的输出语句有所不同3、函数前面要带上asmlinkage标记修改完sys.c文件之后,进入/usr/src/linux-2.4/include/asm-i386目录下,找到unistd.h文件,并在其中添加刚才在sys.c文件中添加的函数的系统调用号,如下所示:、图4图5完成这一步骤之后,接下来要修改第三个文件,也是最后一个文件,entry.S,该文件在/usr/src/linux-2.4/arch/i386/kernel目录下,如图所示:图6打开该文件,并在该文件中添加之前写入sys.c文件中的系统函数的清单号,如下图所示:图7保存退出后,自此则完成了对增加系统调用所涉及的的要修改的文件的修改,完成这步以后,就要开始对修改后的内核进行编译了。

操作系统实验一 向LINUX 内核增加一个系统调用

操作系统实验一 向LINUX 内核增加一个系统调用

操作系统实验一:向Linux内核增加一个系统调用xx711103xx2012年3月18日一、实验目的通过实验,熟悉Linux操作系统的使用,掌握构建与启动Linux内核的方法;掌握用户程序如何利用系统调用与操作系统内核实现通信的方法,加深对系统调用机制的理解;进一步掌握如何向操作系统内核增加新的系统调用的方法,以扩展操作系统的功能。

二、实验内容1.Linux环境下的C或C++编译和调试工具的使用2.向Linux内核增加新的系统调用,系统调用名称和功能自行定义3.Linux新内核的编译、安装和配置4.编写应用程序以测试新的系统调用并输出测试结果三、实验步骤1、安装VirtualBox-4.0.8并在虚拟机上安装ubuntu11.10。

(电脑上本有ubuntu11.10 64位系统,但在编译内核完成后发现参考教程为32位系统,因64位系统与32位系统增加系统调用步骤差别较大,身为初学者的我选择安装虚拟机,并重新编译……)2、安装编译源环境sudo apt-get install build-essential、sudo apt-get install gcc、sudo apt-get install g++编写一个c++或c程序,并使用gcc–o xxx或g++-o xxx进行编译并运行。

3、用sudo apt-get update更新软件源,并用apt-get install linux-source命令下载适合自己的内核。

(当使用过老版本内核时,采用默认的内核配置make oldconfig时,将会造成错误,自己也因此重做一遍)。

4、增加系统调用:第一步:解压文件#cp linux-source-3.0.0.tar.bz2/usr/src拷贝至/usr/src目录#tar xvf linux-source-3.0.0.tar.bz2解压文件第二步:修改源程序,增加系统调用实现#gedit/usr/src/linux-source-3.0.0/kernel/sys.casmlinkage int sys_mycall(int number){printk("hello,my new kernel,xw~!");return number;}第三步:修改头文件,增加系统调用声名#gedit/usr/src/linux-source-3.0.0/arch/x86/kernel/syscall_table_32.S将223行.long sys_ni_syscall改为.long sys_mycall(不要放在其他地方,否侧可能出现错误)第四步:修改系统调用表,注册系统调用。

linux中添加系统调用

linux中添加系统调用
BEA Confidential. | 28
Linux2.6内核添加系统调用
用户空间: 用户空间 1,/usr/include/asm/unistd 末尾加上 #define __NR_cqtest1 #define __NR_cqtest2 280 281 __SYSCALL(__NR_cqtest1, sys_cqtest1) __SYSCALL(__NR_cqtest2, sys_cqtest2) 2,/usr/include/bits/syscall.h 末尾加上 #define SYS_cqtest1 __NR_cqtest1 #define SYS_cqtest2 __NR_cqtest2
在第三个系统调用中采用了prink函数输出一些信息,到 /var/log/messages中.
BEA Confidential. | 8
添加 Linux 系统调用
1 2 3 4 5
添加新函数 更新头文件 针对这个新函数更新系统调用表 重新编译内核 运行测试程序
BEA Confidential. | 9
运行测试程序(2)
编辑源代码如下:
BEA Confidential. | 24
运行测试程序(2)
运行结果如下:
测试程序(3)
编辑源代码如下:
BEA Confidential. | 26
运行测试程序(3)
运行结果如下:
BEA Confidential. | 27
BEA Confidential. | 29
Thank You
int get_user( var, ptr ); int put_user( var, ptr );
在第二个系统调用中采用了put_user函数,向一块用户内存写 数据.

linux添加系统调用实验步骤

linux添加系统调用实验步骤

首先,进入到内核源码目录/usr/src/linux-2.6.34中,添加自己的系统调用号。

lyh@lyh:~$ cd /usr/src/linux-2.6.34/系统调用号在unistd_32.h文件中定义。

内核中每个系统调用号都是以“__NR_"开头的,在该文件中添加自己的系统调用号lyh@lyh:/usr/src/linux-2.6.34$ sudo vim arch/x86/include/asm/unistd_32.h#define __NR_pwritev 334#define __NR_rt_tgsigqueueinfo 335#define __NR_perf_event_open 336#define __NR_recvmmsg 337#define __NR_mycall 338#ifdef __KERNEL__#define NR_syscalls 339在内核源文件中该行为#define NR_syscalls 338,在系统调用执行的过程中,system_call()函数会根据该值来对用户态进程的有效性进行检查。

如果这个号大于或等于NR_syscalls,系统调用处理程序终止。

所以应该将原来的#define NR_syscalls 338修改为#define NR_syscalls 339其次,在系统调用表中添加相应的表项(1)lyh@lyh:/usr/src/linux-2.6.34$ sudo vim arch/x86/kernel/syscall_table_32.SENTRY(sys_call_table).long sys_restart_syscall.long sys_exit………………(这里省略了部分).long sys_rt_tgsigqueueinfo.long sys_perf_event_open.long sys_recvmmsg.long sys_mycall(2)lyh@lyh:/usr/src/linux-2.6.34$ sudo vimarch/h8300/kernel/syscalls.S#include <linux/sys.h>#include <asm/linkage.h>……………………(这里省略了部分).long SYMBOL_NAME(sys_vmsplice).long SYMBOL_NAME(sys_ni_syscall).long SYMBOL_NAME(sys_getcpu).long SYMBOL_NAME(sys_ni_syscall).long SYMBOL_NAME(sys_mycall)最后,实现系统调用服务例程。

向Linux内核添加系统调用函数

向Linux内核添加系统调用函数

向Linux内核添加系统调用函数实验环境:虚拟机VMware 6.0操作系统Ubuntu9.10(内核版本2.6.31-14-generic)修改内核版本2.6.31.12实验步骤:1.下载Linux内核:在终端中输入命令sudo apt-get install linux-source,下载的文件在/usr/src 目录下。

(注:如果源没有更新的,在下载之前请先更新源。

)2.将内核代码解压缩:例如下载的内核文件为linux-source-2.6.31.tar.bz2,运行解压命令tar –jxvf linux-source-2.6.31.tar.bz2。

解压出的文件夹为/usr/src/linux-source-2.6.31。

3.修改/usr/src/linux-source-2.6.31/kernel/sys.c文件,例如在文件末尾增加一个系统响应函数。

asmlinkage int sys_mycall(int number){printk("这是***编写的的系统调用函数");//printk是内核中日志级别的输出函数return number;}4.在/usr/src/linux-source-2.6.31/arch/x86/kernel/syscall_table_32.S中添加:.long sys_mycall。

5.在/usr/src/linux-2.6.31/arch/x86/include/asm/unistd_32.h中添加:#define __NR_mycall 序号(例如337),添加系统调用的入口参数(注意:其中会顺序定义入口参数的序号,添加的序号是在原有最大值的基础上+1)6.编译内核:首先切换到解压的内核目录下。

第一步:make mrproper 清除内核中不稳定的目标文件,附属文件及内核配置文件第二步:make clean 清除以前生成的目标文件和其他文件第三步:make oldconfig 采用默认的内核配置第四步:make bzImage 编译内核第五步:make modules 编译模块第六步:make modules_install 安装模块总共需要的编译的时间大约为两个小时。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

选题要求:在Linux内核中增加一个系统调用,并编写对应的linux应用程序。

利用该系统调用能够遍历系统当前所有进程的任务描述符,并按进程父子关系将这些描述符所对应的进程id(PID)组织成树形结构显示。

目录
一.程序的主要设计思路,实现方式 (4)
1.1 添加系统调用的两种方法 (4)
1.1.1编译内核法 (4)
1.1.2内核模块法 (4)
1.2 程序的主要设计思路 (5)
1.3 环境 (5)
二.程序的模块划分,及对每个模块的说明 (5)
2.1 通过内核模块实现添加系统调用 (5)
2.1.1修改系统调用的模块 (5)
2.1.2获取sys_call_table的地址 (5)
2.1.3清除内存区域的写保护 (6)
2.2 编写系统调用指定自己的系统调用 (7)
2.2.1内核的初始化函数 (7)
2.2.2自己的系统调用服务例程 (7)
2.2.3移除内核模块时,将原有的系统调用进行还原 (9)
2.2.4模块注册相关 (9)
2.3 编写用户态的测试程序 (9)
2.4 编写Makefile文件 (10)
三.所遇到的问题及解决的方法 (11)
3.1 进程个数确定 (11)
3.2 被更改的系统调用号的选择 (11)
3.3 获取系统调用表的地址 (11)
3.4 内核和用户态数据交换 (11)
四.程序运行结果及使用说明 (11)
4.1 将编译出来的内核模块hello.ko加载到内核中 (11)
4.2通过dmesg查看输出信息是否正确 (11)
4.3运行测试程序,输出树状打印结果(部分结果截图) (12)
4.4卸载自定义模块 (13)
五.附录 (14)
5.1 内核模块程序hello.c (14)
5.2 测试程序hello_test.c (17)
5.3 Makefile文件 (17)
一.程序的主要设计思路,实现方式
1.1 添加系统调用的两种方法
1.1.1编译内核法
编写好源码之后
以上准备工作做完之后,然后就要进行编译内核了,以下是编译内核的一个过程
1.1.2内核模块法
内核模块可以作为独立程序来编译的函数和数据类型的集合。

之所以提供模块机制,是因为Linux本身是一个单内核。

单内核由于所有内容都集成在一起,效率很高,但可扩展性和可维护性相对较差,模块机制可以弥补这一缺陷。

Linux模块可以通过静态或动态的方法加载到内核空间,静态加载是指在内核启动过程中加载;动态加载是指在内核运行的过程中随时加载。

一个模块被加载到内核中时,就成为内核代码的一部分。

模块加载入系统时,系统修改内核中的符号表,将新加载的模块提供的资源和符号添加到内核符号表中,以便模块间通信。

这种方法是采用系统调用拦截的一种方式,改变某一个系统调用号对应的服务程序为我们自己的编写的程序,从而相当于添加了我们自己的系统调用。

下面的内容,会详述用内核模块法实现目标的过程。

1.2 程序的主要设计思路
程序分三部分,一部分是通过内核模块实现添加系统调用,二是编写系统调用指定自己的系统调用,最后是编写用户态的测试程序。

1.3 环境
Ubuntu14.04 + 3.13.0内核版本
内核版本:
二.程序的模块划分,及对每个模块的说明
2.1 通过内核模块实现添加系统调用
这种方法其实是系统调用拦截的实现。

系统调用服务程序的地址是放在sys_call_table 中通过系统调用号定位到具体的系统调用地址,那么我们通过编写内核模块来修改sys_call_table中的系统调用的地址为我们自己定义的函数的地址,就可以实现系统调用的拦截。

通过模块加载时,将系统调用表里面的那个系统调用号的那个系统调用号对应的系统调用服务例程改为我们自己实现的系统历程函数地址。

2.1.1修改系统调用的模块
在/usr/include/i386-linux-gnu/asm/unistd_32.h文件中查看系统调用序号:
找到结果(部分截图):
可以看到,222号和223号系统调用是空的,因此选取223作为新的系统调用号。

2.1.2获取sys_call_table的地址
在/boot/System.map-3.16.0-30-generic查看系统调用表的内存地址:
找到结果:
为0xc165e140
2.1.3清除内存区域的写保护
得到了sys_call_table的地址,该符号对应的内存区域是只读的。

所以我们要修改它,必须对它进行清除写保护,这里介绍两种方法:
第一种方法:我们知道控制寄存器cr0的第16位是写保护位。

cr0的第16位置为了禁止超级权限,若清零了则允许超级权限往内核中写入数据,这样我们可以再写入之前,将那一位清零,使我们可以写入。

然后写完后,又将那一位复原就行了。

//使cr0寄存器的第17位设置为0(即是内核空间可写)
unsigned int clear_and_return_cr0(void)
{
unsigned int cr0 = 0;
unsigned int ret;
asm("movl %%cr0, %%eax":"=a"(cr0));
//将cr0寄存器的值移动到eax寄存器中,同时输出到cr0变量中
ret = cr0;
cr0 &= 0xfffeffff;//将cr0变量的第17位清0
asm("movl %%eax, %%cr0"::"a"(cr0));
//将cr0变量的值放入寄存器eax中,并且放入cr0寄存器中
return ret;
}
//读取val的值到eax寄存器,再将eax寄存器的值放入cr0寄存器中---改变内核地址空间参数
void setback_cr0(unsigned int val)
{
asm volatile("movl %%eax, %%cr0"::"a"(val));
}
第二种方法:通过设置虚拟地址对应的也表项的读写属性来设置。

2.2 编写系统调用指定自己的系统调用
2.2.1内核的初始化函数
此函数内采用的是2.1.3中的第一种方法。

2.2.2自己的系统调用服务例程
部分一:创建进程树
void processtree(struct task_struct * p,int b);
结果需要以树状形式展示所有进程的父子关系。

为此,我们定义processtree()递归函数来访问遍历,并且将结果存储在数组中,以便提供给用户态访问。

其中,特别使用了宏:
ptr是指向list_head类型链表的指针;
type为一个结构;
member为结构type中的一个域,类型为list_head;
这个宏返回指向type结构的指针。

目的:从一个结构的成员指针找到其容器的指针
部分二:创建自己的系统调用服务
asmlinkage long sys_mycall(char __user * buf);
在sys_mycall()中,从当前进程开始,递归调用processtree()函数,将进程信息存储在数组中。

然后利用copy_to_user函数将内核信息传递给用户态下,用户态下的测试程序对结果进行展示。

2.2.3移除内核模块时,将原有的系统调用进行还原
2.2.4模块注册相关
●模块构造函数
执行insmod或modprobe指令加载内核模块时会调用的初始化函数。

函数原型必须是module_init(),内是函数指针。

●模块析构函数
执行rmmod指令卸载模块时调用的函数。

函数原型是module_exit();
●模块许可声明
函数原型是MODULE_LICENSE(),告诉内核程序使用的许可证,不然在加载时它会提示该模块污染内核。

一般会写GPL。

2.3 编写用户态的测试程序
2.4 编写Makefile文件
三.所遇到的问题及解决的方法
3.1 进程个数确定
系统可运行的最大进程数,通过ulimit –u 查看有7863个
我们通过ps –ef|wc –l命令实际查看当前运行进程数量为191个
存储进程信息的数组大小为512是够用的。

3.2 被更改的系统调用号的选择
见2.1.1。

3.3 获取系统调用表的地址
见2.1.2。

3.4 内核和用户态数据交换
我们在内核模块程序中,将进程遍历信息存储在数组中,然后需要将其传递给用户态下。

采用copy_from_user()和copy_to_user()这两个函数,这两个函数负责在用户空间和内核空间传递数据。

因此我们在测试程序中,将空数组a的地址作为参数传递给内核模块程序,在内核中使用copy_to_user()函数将内核中的数组信息传递给用户态下的地址。

四.程序运行结果及使用说明
4.1 将编译出来的内核模块hello.ko加载到内核中
加载内核模块命令:
insmod hello.ko
4.2通过dmesg查看输出信息是否正确
4.3运行测试程序,输出树状打印结果(部分结果截图)
4.4卸载自定义模块卸载内核模块命令:insmod hello.ko
五.附录
5.1 内核模块程序hello.c
5.2 测试程序hello_test.c
5.3 Makefile文件。

相关文档
最新文档