为arm linux 2.6.24 添加系统调用
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内核并添加一个系统调用

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内核增加一个系统调用的具体步骤。
二、增加系统调用的步骤1.编写系统调用的具体实现代码首先,我们需要编写一个具体的系统调用的实现代码。
在LINUX内核中,系统调用的实现代码通常位于内核的/syscalls目录下。
我们可以在该目录下新建一个.c文件,编写我们自己的系统调用代码。
2.修改内核源代码3.更新系统调用表每个系统调用都在内核中有一个唯一的标识符,存储在一个叫做系统调用表的地方。
我们需要更新系统调用表,将新增的系统调用添加到表中。
这样,用户程序才能够通过系统调用号来调用新增的系统调用。
4.重新编译内核在修改完内核源代码后,我们需要重新编译内核。
这通常涉及到一些繁琐的步骤,例如配置内核选项、编译内核、安装内核等。
在重新编译内核之后,我们需要重新启动计算机,使新的内核生效。
5.修改用户程序最后,我们需要修改用户程序,以便能够调用新增的系统调用。
用户程序通常是通过C语言编写的,我们可以在用户程序的代码中添加对新增系统调用的调用代码。
三、实验结果在完成上述步骤后,我们就成功地向LINUX内核增加了一个系统调用。
用户程序可以通过系统调用调用自己新增的系统调用,从而实现特定的功能。
总结:本文介绍了向LINUX内核增加一个系统调用的具体步骤,包括编写系统调用的具体实现代码、修改内核源代码、更新系统调用表、重新编译内核和修改用户程序。
在实施这些步骤之前,我们需要对操作系统和内核的相关概念有一定的了解,并具备一定的编程能力。
增加系统调用实验报告(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. 修改系统调用表接下来,我们需要修改内核源代码中的系统调用表,以注册我们创建的系统调用。
(完整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内核模块法内核模块可以作为独立程序来编译的函数和数据类型的集合。
添加系统调用(模块添加法2.6内核)

添加系统调用(模块添加法fedora10:2.6.27.5内核)
一、为什么要使用内核模块的方式添加系统调用?
⏹编译内核的方式费时间,一般的PC机都要两三个小时。
⏹不方便调试,一旦出现问题前面的工作都前功尽弃。
二、用内核模块的方式实现系统调用有个前提,就是系统必须导出sys_call_table 内核符号,但是在2.6内核和2.4.18以上版本中,sys_call_table不再导出。
也就是说模块中不能再通过简单的extern void *sys_call_table[];来获得系统调用
表地址。
但是,即使内核不导出sys_call_table,也可以在内存中找到它的地址,下面是它的实现方法:
第1步:编写syscall_my.c程序:
pptprogram/syscall/module_syscall/syscall_my.c
第2步:编写Makefie文件
见pptprogram/syscall/module_syscall/Makefile
第3步.执行make命令编译模块
第4步:执行insmod命令插入模块,此时会把自己编写的系统调用插入到系统调用表中。
操作系统实验 为linux添加一个系统调用

进程控制的基础
Linux进程创建及分析
第一个进程事实上就是Linux kernel本身,像所有其 他的进程一样,Linux kernel本身也有代码段,数据段, 堆栈。只不过Linux kernel这个进程自己来维护这些段, 这一点是与其他进程不同的地方。第一个进程是唯一一个 静态创建的进程,在Linux kernel编写并且编译的时候创 建。 在Linux内核中,这个进程被称作init task/thread(pid 0)。 系统中其他的进程都通过复制父进程来产生,Linux 提供两个系统调用fork和clone来实现这个功能,广义上, 我们都叫它们fork( ),这也是Unix系统的传统叫法,表示 一个进程分叉又产生两个进程。对fork( )具体使用方法我 们稍后阐述。
关键点五
一般来说,在fork之后时父进程先执行还是子进程先执行 是不确定的。这取决于内核所使用的调度算法。如果要求父子 进程之间相互同步,则要求某种形式的进程之间通信。
进程的创建和销毁——exec理解
关键点一
fork( )创建了一个程序,但是如果这个子程序只能 局限在自身的代码段范围之中(不能去执行别的程序), 那么fork( )也就没有太多的实际意义。在Linux中,exec 调用用于从一个进程的地址空间中执行另外一个进程, 覆盖自己的地址空间。有了这个系统调用,shell就可以 使用fork+exec 的方式执行别的用户程序了。一个进程 使用exec执行别的应用程序之后,它的代码段,数据段, bss段和堆栈段都被新程序覆盖,唯一保留的是进程号。
进程的创建和销毁——fork分析
1. 为新进程分配一些基本的数据结构。具体到Linux,最重要的 比如一个新的进程好pid,一个task_struct和一个8K大小的联合 体(存放thread_info和内核栈)等。 2. 共享或者拷贝父进程的资源,包括环境变量,当前目录,打 开的文件,信号量以及处理函数等。 3. 为子进程创建虚拟地址空间。子进程可能跟父进程共享代码 段,数据段也可能采用COM(写时拷贝)的策略使fork( )的速 度和灵活性得到提高。 4. 为子进程设置好调度相关的信息,使得子进程在适当的时候 独立于父进程,能被独立调度。 5. fork( )的返回。对于父进程来说,for( )函数直接返回子进程的 pid;而对于子进程来说,是在子进程被第一次调度执行的时候, 返回0。
linux arm上系统调用流程

linux arm上系统调用流程
在LinuxARM架构中,系统调用是用户空间程序与内核进行交互的重要方式之一。
其流程主要包括以下几个步骤:
1、用户程序通过系统调用号和参数向内核发起系统调用请求。
2、内核根据系统调用号判断调用的具体功能,并将参数从用户空间复制到内核空间。
3、内核执行指定的系统调用功能,并将执行结果返回给用户程序。
4、用户程序处理系统调用的执行结果。
在ARM架构中,系统调用是通过软中断(SWI)的方式实现的。
具体来说,用户程序会在执行到相应的系统调用指令时触发一个软中断,中断处理程序会根据系统调用号调用相应的内核函数来完成系统调用的处理。
在Linux内核中,系统调用函数通常被封装在一个系统调用表中,用户程序在发起系统调用请求时会通过系统调用号来索引相应的系统调用函数。
需要注意的是,在ARM架构中,系统调用的参数传递还有一种特殊的方式,即通过寄存器来传递参数,而不是通过堆栈。
具体来说,r0-r3寄存器用于传递前4个参数,r4-r11寄存器用于传递后续的参数,r7寄存器则用于传递系统调用号。
总之,对于ARM架构上的Linux系统而言,系统调用是实现用户程序与内核通信的重要方式之一,理解其调用流程和参数传递方式对于深入了解Linux系统的运作原理具有重要意义。
给linux添加一个系统调用

一、实现思路:给linux添加一个系统调用,也就是为linux增加一个api函数。
这样需要修改linux的内核,然后通过编译就会形成一个新内核,在新内核里即可调用自己添加的api函数。
二、实验步骤:(1)cd /usr/src/linux/kernel(2)vi sys.c 并添加如下一个函数:asmlinkage int sys_mycall(int num){if(num > 0){return 2;}else{return 13061032;}}(3)cd /usr/src/linux/arch/i386/kernel(4)vi entry.S 并添加如下代码.long SYMBOL_NAME(sys_mycall)(5)在头文件中增加申明:cd /usr/include/asm vi unistd.h添加:#define __NR_mycall 191(6)编译内核:#make mrproper /* clean old config info */#make clean /* clean old object file */#make menuconfig /* do nothing,just exit and save config,all use default */#make dep /* binding the configuration info */#make bzImage /* it should work. */(7)编译完成后,将新内核文件和新的系统符号表拷贝到/boot目录,如下:#cp arch/i386/boot/bzimage /boot/bzimage_00#mkinitrd /boot/bzImage_00.img 2.2.14-15mdk(8)修改系统配置文件(/etc/lilo.conf):在lilo.conf文件末尾添加如下代码:image = /boot/bzImage_00label = linux-oyzroot = /dev/sda5initrd = /boot/bzImage_00.imgappend = “”read-only(9)使用超级用户运行:/sbin/lilo,然后重新启动:reboot(10)在启动的boot页面,Tab选择linux-oyz启动。
(cc)Linux下增加系统调用的方法

(cc)Linux下增加系统调用的方法.txt如果不懂就说出来,如果懂了,就笑笑别说出来。
贪婪是最真实的贫穷,满足是最真实的财富。
幽默就是一个人想哭的时候还有笑的兴致。
(cc)Linux下增加系统调用的方法1.linux系统调用的基本原理linux的系统调用形式与POSIX兼容,也是一套C语言函数名的集合。
然而,linux系统调用的内部实现方式却与DOC的INT 21H相似,它是经过INT 0X80H软中断进入后,再根据系统调用号分门别类地服务。
从系统分析的角度,linux的系统调用涉及4个方面的问题。
(1)与系统调用有关的数据结构和函数函数名以“sys_”开头,后跟该系统调用的名字。
例如,系统调用fork()的响应函数是sys_fork()(见Kernel/fork.c),exit()的响应函数是sys_exit()(见kernel/fork.c)。
文件include/asm/unisted.h为每个系统调用规定了唯一的编号。
假设用name表示系统调用的名称,那么系统调用号与系统调用响应函数的关系是:以系统调用号_NR_name作为下标,可找出系统调用表sys_call_table(见arch/i386/kernel/entry.S)中对应表项的内容,它正好是该系统调用的响应函数sys_name 的入口地址。
系统调用表sys_call_table记录了各sys_name函数在表中的位置,共190项。
有了这张表,就很容易根据特定系统调用在表中的偏移量,找到对应的系统调用响应函数的入口地址。
系统调用表共256项,余下的项是可供用户自己添加的系统调用空间。
(2)进程的系统调用命令转换为INT 0x80中断的过程宏定义_syscallN()见include/asm/unisted.h)用于系统调用的格式转换和参数的传递。
N 取0~5之间的整数。
参数个数为N的系统调用由_syscallN()负责格式转换和参数传递。
操作系统项目:向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系统增加系统调用之前的一段时间就做过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内核增加一个系统调用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中添加系统调用

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函数,向一块用户内存写 数据.
ubuntu系统中添加新的系统调用2.6.33.1(linux)

如果用户在Linux中添加新的系统调用,应该遵循几个步骤才能添加成功,下面几个步骤详细说明了添加系统调用的相关内容。
(1) 添加源代码第一个任务是编写加到内核中的源程序,即将要加到一个内核文件中去的一个函数,该函数的名称应该是新的系统调用名称前面加上sys_标志。
假设新加的系统调用为mycall(int number),在/usr/src/linux/kernel/sys.c文件中添加源代码,如下所示:asmlinkage int sys_mycall(int number){return number;}作为一个最简单的例子,我们新加的系统调用仅仅返回一个整型值。
(2) 连接新的系统调用添加新的系统调用后,下一个任务是使Linux内核的其余部分知道该程序的存在。
为了从已有的内核程序中增加到新的函数的连接,需要编辑两个文件。
在我们所用的Linux内核版本(RedHat 6.0,内核为2.2.5-15)中,第一个要修改的文件是:/usr/src/linux/include/asm-i386/unistd.h该文件中包含了系统调用清单,用来给每个系统调用分配一个唯一的号码。
文件中每一行的格式如下:#define __NR_name NNN其中,name用系统调用名称代替,而NNN则是该系统调用对应的号码。
应该将新的系统调用名称加到清单的最后,并给它分配号码序列中下一个可用的系统调用号。
我们的系统调用如下:#define __NR_mycall 191系统调用号为191,之所以系统调用号是191,是因为Linux-2.2内核自身的系统调用号码已经用到190。
(在后来的版本中系统调用一般都是插入表中作为倒数第二个调用的。
我使用ubuntu9-10,内核为2.6.33.1实现的)第二个要修改的文件是:/usr/src/linux/arch/i386/kernel/entry.S该文件中有类似如下的清单:.long SYMBOL_NAME()该清单用来对sys_call_table[]数组进行初始化。
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内核添加系统调用函数实验环境:虚拟机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 安装模块总共需要的编译的时间大约为两个小时。
linux增加系统调用方法

linux 系统调用的原理:系统调用,说的是操作系统提供给用户空间访问内核空间资源的接口函数,例如linux中的open,read函数都可看作是系统调用,open和read中其实还封装了sys_open,sys_read.系统调用在windows中称做接口函数。
系统调用的出现主要是为了保护内核空间不被用户空间“恣意”访问,提供给用户有限的访问权限,访问方式。
有时我们写应用程序感觉没用到什么系统调用,其实在我们使用的C标准函数都是调用了系统调用,进行了封装。
Linux中 实现系统调用利用了0x86体系结构中的软件中断[4]。
软件中断和我们常说的中断(硬件中断)不同之处在于——它是通过软件指令触发而并非外设引发的中 断,也就是说,又是编程人员开发出的一种异常,具体的讲就是调用int $0x80汇编指令,这条汇编指令将产生向量为128的编程异常。
具体的内部机制,不做介绍,有兴趣可自行查阅分析。
Linux 下添加自己的系统调用对于系统工程师来说,有时需要自己添加特定的系统函数来扩充系统功能,所以下面讲解下如何添加自己的系统调用,内核采用2.6以上版本,请注意2.4与其有所不同。
1.编写新的系统调用首先准备2.6以上内核源码放到/usr/src/下,要增加系统调用是:int myCall(),其功能是在控制终端屏幕上显示hello world,执行成功后返回0。
将新函数放入系统文件kernel/sys.c中,新函数代码添加如下:asmlingkage int sys_myCall(){console_print("hello world\n");return 0;}函数名以“sys_”开头,后跟该系统调用的名字.2连接新的系统调用编写了新的系统调用过程后,下一项任务是使内核的其余部分知道这一程序的存在,然后重建包含新的系统调用的内核。
为了把新的函数连接到已有的内核中去, 需要编辑2个文件:1).inculde/asm/unistd.h在这个文件中加入#define__NR_myCall 191注意“191”是我们的系统调用号,要根据具体情况进行修改,比如以前最大的系统调用号是190,那我们添加的就可以为191.修改#define NR_systemcalls 为原来的值加1.2).kernel/entry.s这个文件用来对指针数组初始化,在这个文件中增加一行:.long SYMBOL_NAME(_sys_myCall)将.rept NR_syscalls-190改为NR_SYSCALLS-191然后重新编译和运行新内核。
编译Linux2_6内核并添加一个系统调用

2011年第4期福建电脑编译Linux2.6内核并添加一个系统调用张伟华,王海英,高静(河南财经政法大学成功学院河南郑州451200)【摘要】:本文以实例来详细描述了从准备一直到使用新内核的Linux2.6内核编译过程,然后介绍了添加系统调用的实现步骤,最后给实验结果。
【关键词】:Linux,内核,编译内核,系统调用引言Linux[1]作为一个自由软件,在广大爱好者的支持下,内核版本不断更新也不断增大,通过编译内核可以轻易地对它进行修改,使我们能够根据自己的要求度身定制一个更高效、更稳定的内核。
系统调用[2]是用户进程与系统之间的接口,它们在内核中实现,其主要目的是使得用户可以使用操作系统提供的操作底层设备的功能。
用户程序肯定要操作系统设备,没有系统调用,程序员就需要了解硬件细节才能写出强大程序,这显然不利于将精力集中在解决问题上。
学习操作系统设计技术的有效方法就是读懂并修改Linux的源代码,编译内核和添加系统调用就是比较基础的内容,本文就以这两部分来展开:一是编译内核,二是添加系统调用。
一、编译内核1.到ftp:///pub/linux/kernel/v2.6/中找到相关版本的压缩包linux-2.6.15.1.tar.bz2或linux-2.6.15.1.tar.gz2.首先cp命令或mv命令将压缩包放到/usr/src/ redhat/SOURCES/下,解压缩包:tar-jxvf linux-2.6.15.1.tar.bz2(对应于.bz2文件)或tar-xzvf linux-2.6.15.1. tar.gz(对应于.tar.gz(.tgz)文件)3.在/usr/src/redhat/SOURCES/下得到解压后的文件linux-2.6.15.1,并设置路径:cd/usr/src/redhat/ SOURCES/linux-2.6.15.1,一定要保证路径正确,make 的有关命令一般在此目录下。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
为arm linux 2.6.24 添加系统调用
# gedit arch/arm/kernel/sys_arm.c
----------------------------------------------------------- asmlinkage long sys_arm_fadvise64_64(int fd, int advice,
loff_t offset, loff_t len)
{
return sys_fadvise64_64(fd, offset, len, advice);
}
asmlinkage int sys_kmd(unsigned int p_addr)
{
printk("p_addr = 0x%x\n", p_addr);
return p_addr;
}
# gedit include/asm-arm/unistd.h
-----------------------------------------------------------
#define __NR_fallocate (__NR_SYSCALL_BASE+352)
#define __NR_kmd (__NR_SYSCALL_BASE+353)
# gedit arch/arm/kernel/calls.S
-----------------------------------------------------------
CALL(sys_fallocate)
CALL(sys_kmd)
测试提供调用
-----------------------------------------------------------
#define _GNU_SOURCE /* or _BSD_SOURCE or _SVID_SOURCE */ #include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
#define __NR_kmd (__NR_SYSCALL_BASE+353)
int kmd (unsigned int p_addr)
{
syscall (__NR_kmd, p_addr);
return 0;
}
int main ()
{
kmd (0x100000);
}
# arm-linux-gcc kmd.c -static
# cp a.out /tftpboot/
# tftp -g -r a.out 192.168.1.160
# ./a.out
p_addr = 0x100000
#if 1
#define DISP_LINE_LEN (16)
#define MAX_LINE_LENGTH_BYTES (64)
#define DEFAULT_LINE_LENGTH_BYTES (16)
#define int8_t char
#define int16_t short
#define int32_t long
#define int64_t long long
#define uint8_t u_char
#define uint16_t u_short
#define uint32_t u_long
#define uint64_t unsigned long long
#define t_scalar_t int
#define t_uscalar_t unsigned int
#define uintptr_t unsigned long
/*
* Print data buffer in hex and ascii form to the terminal.
*
* data reads are buffered so that each memory address is only read once. * Useful when displaying the contents of volatile registers.
*
* parameters:
* addr: Starting address to display at start of line
* data: pointer to data buffer
* width: data value width. May be 1, 2, or 4.
* count: number of values to display
* linelen: Number of values to print per line; specify 0 for default length
*/
int print_buffer (ulong addr, void *data, uint width, uint count, uint linelen)
{
uint8_t linebuf[MAX_LINE_LENGTH_BYTES];
uint32_t *uip = (void *) linebuf;
uint16_t *usp = (void *) linebuf;
uint8_t *ucp = (void *) linebuf;
int i;
if (linelen * width > MAX_LINE_LENGTH_BYTES)
linelen = MAX_LINE_LENGTH_BYTES / width;
if (linelen < 1)
linelen = DEFAULT_LINE_LENGTH_BYTES / width;
while (count)
{
printk ("%08lx:", addr);
/* check for overflow condition */
if (count < linelen)
linelen = count;
/* Copy from memory into linebuf and print hex values */
for (i = 0; i < linelen; i++)
{
if (width == 4)
{
uip[i] = *(volatile uint32_t *) data;
printk (" %08x", (unsigned int)uip[i]);
}
else if (width == 2)
{
usp[i] = *(volatile uint16_t *) data;
printk (" %04x", usp[i]);
}
else
{
ucp[i] = *(volatile uint8_t *) data;
printk (" %02x", ucp[i]);
} data += width;
}
#if 0
/* Print data in ASCII characters */
printk (" ");
for (i = 0; i < linelen * width; i++)
fputc (isprint (ucp[i]) && (ucp[i] < 0x80) ? ucp[i] : '.', stdout);
fputc ('\n', stdout);
#endif
printk("\n");
/* update references */
addr += linelen * width;
count -= linelen;
}
return 0;
}
asmlinkage int sys_kmd(unsigned int v_addr)
{
ulong length = 64, p_addr = 0, size = 4;
if (0 == v_addr)
{
printk("v_addr = %x\n", (unsigned int)v_addr);
return -1;
}
p_addr = virt_to_phys((void *)v_addr);
printk("v_addr <--> p_addr\n");
printk("%08x <--> %08x\n", (unsigned int)v_addr,
(unsigned int)p_addr);
print_buffer (v_addr, (void *) v_addr, size, length,
DISP_LINE_LEN / size);
return 0;
}
#endif。