一、 什么是体系调用
在Linux的国际里,咱们经常会遇到体系调用这一术语,所谓体系调用,便是内核供给的、功用十分强壮的一系列的函数。这些体系调用是在内核中完结的,再经过必定的办法把体系调用给用户,一般都经过门(gate)堕入(trap)完结。体系调用便是用户空间运用程序和内核供给的服务之间的一个接口。因为服务是在内核中供给的,因而无法履行直接调用;相反,您有必要运用一个进程来跨过用户空间与内核之间的边界。在特定架构中完结此功用的办法会有所不同。因而,本文将着眼于最通用的架构 —— i386。
二、 体系调用的作用
体系调用在Linux体系中发挥着巨大的作用,假如没有体系调用,那么运用程序就失去了内核的支撑。咱们在编程时用到的许多函数,如fork、open等这些函数终究都是在体系调用里完结的,这儿咱们说到了两个函数,即fork和exit,这两函数都是glibc中的函数,可是假如咱们盯梢函数的履行进程,看看glibc对fork和exit函数的完结就能够发现在glibc的完结代码里都是选用软中止的办法堕入到内核中再经过体系调用完结函数的功用的。具体进程咱们在体系调用的完结进程会具体的讲到。
由此可见,体系调用是用户接口在内核中的完结,假如没有体系调用,用户就不能运用内核。
三、 体系调用的实践及调用进程
具体叙述体系调用的之前也讲一下Linux体系的一些维护机制。
Linux体系在CPU的维护形式下供给了四个特权等级,现在内核都只用到了其间的两个特权等级,别离为“特权级0”和“特权级3”,等级0也便是咱们一般所讲的内核形式,等级3也便是咱们一般所讲的用户形式。区分这两个等级主要是对体系供给维护。内核形式能够履行一些特权指令和进入用户形式,而用户形式则不能。
这儿特别提出的是,内核形式与用户形式别离运用自己的仓库,当发生形式切换的时分一起要进行仓库的切换。每个进程都有自己的地址空间(也称为进程空间),进程的地址空间也分为两部分:用户空间和体系空间,在用户形式下只能拜访进程的用户空间,在内核形式下则能够拜访进程的悉数地址空间,这个地址空间里的地址是一个逻辑地址,经过体系段面式的办理机制,拜访的实践内存要做二级地址转化,即:逻辑地址、线性地址、物理地址。
体系调用关于内核来说就相当于函数,咱们是要害问题是从用户形式到内核形式的转化、仓库的切换以及参数的传递。
四、引起体系调用的两种途径
(1)int $0×80 , 旧式linux内核版别中引起体系调用的仅有办法
(2)sysenter汇编指令
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mlyy225/archive/2010/01/07/5148911.aspx
如安在Linux中增加新的体系调用
体系调用是运用程序和操作体系内核之间的功用接口。其主要意图是使得用户能够运用操作体系供给的有关设备办理、输入/输入体系、文件体系和进程操控、通讯以及存储办理等方面的功用,而不必了解体系程序的内部结构和有关硬件细节,然后起到减轻用户担负和维护体系以及进步资源运用率的作用。
Linux操作体系作为自由软件的代表,它优秀的功能使得它的运用日益广泛,不只得到专业人士的必定,并且商业化的运用也是如火如荼。在Linux中,大部分的体系调用包括在Linux的libc库中,经过规范的C函数调用办法能够调用这些体系调用。那么,对Linux的本站来说,如安在Linux中增加新的体系调用呢?
1 Linux体系调用机制
在Linux体系中,体系调用是作为一种反常类型完结的。它将履行相应的机器代码指令来发生反常信号。发生中止或反常的重要作用是体系主动将用户态切换为核心态来对它进行处理。这便是说,履行体系调用反常指令时,主动地将体系切换为核心态,并组织反常处理程序的履行。
Linux用来完结体系调用反常的实践指令是:
Int x80
这一指令运用中止/反常向量号128(即16进制的80)将操控权搬运给内核。为到达在运用体系调用时不必用机器指令编程,在规范的C言语库中为每一体系调用供给了一段短的子程序,完结机器代码的编程作业。事实上,机器代码段十分简略。它所要做的作业只是将送给体系调用的参数加载到CPU寄存器中,接着履行int x80指令。然后运转体系调用,体系调用的回来值将送入CPU的一个寄存器中,规范的库子程序获得这一回来值,并将它送回用户程序。
为使体系调用的履行成为一项简略的使命,Linux供给了一组预处理宏指令。
它们能够用在程序中。这些宏指令取必定的参数,然后扩展为调用指定的体系调用的函数。
这些宏指令具有相似下面的称号格局:
_syscallN(parameters)
其间N是体系调用所需的参数数目,而parameters则用一组参数替代。这些参数使宏指令完结适合于特定的体系调用的扩展。例如,为了树立调用setuid()体系调用的函数,应该运用:
_syscall1( int, setuid, uid_t, uid )
syscallN( )宏指令的第1个参数int阐明发生的函数的回来值的类型是整型,第2个参数setuid阐明发生的函数的称号。后边是体系调用所需求的每个参数。这一宏指令后边还有两个参数uid_t和uid别离用来指定参数的类型和称号。
别的,用作体系调用的参数的数据类型有一个约束,它们的容量不能超过四个字节。这是因为履行int ?{GetProperty(Content)}x80指令进行体系调用时,一切的参数值都存在32位的CPU寄存器中。运用CPU寄存器传递参数带来的另一个约束是能够传送给体系调用的参数的数目。这个约束是最多能够传递5个参数。所以Linux总共界说了6个不同的_syscallN()宏指令,从_syscall0()、_syscall1()直到_syscall5()。
一旦_syscallN()宏指令用特定体系调用的相应参数进行了扩展,得到的成果是一个与体系调用同名的函数,它能够在用户程序中履行这一体系调用。
2 增加新的体系调用
假如用户在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。
第二个要修正的文件是:
/usr/src/linux/arch/i386/kernel/entry.S
该文件中有相似如下的清单:
.long SYMBOL_NAME()
该清单用来对sys_call_table[]数组进行初始化。该数组包括指向内核中每个体系调用的指针。这样就在数组中增加了新的内核函数的指针。咱们在清单最终增加一行:
.long SYMBOL_NAME(sys_mycall)
(3) 重建新的Linux内核
为使新的体系调用收效,需求重建Linux的内核。这需求以超级用户身份登录。
#pwd
/usr/src/linux
#
超级用户在当前作业目录(/usr/src/linux)下,才干够重建内核。
#make config
#make dep
#make clearn
#make bzImage
编译结束后,体系生成一可用于装置的、紧缩的内核映象文件:
/usr/src/linux/arch/i386/boot/bzImage
(4) 用新的内核发动体系
要运用新的体系调用,需求用重建的新内核从头引导体系。为此,需求修正/etc/lilo.conf文件,在咱们的体系中,该文件内容如下:
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=50
image=/boot/vmlinuz-2.2.5-15
label=linux
root=/dev/hdb1
read-only
other=/dev/hda1
label=dos
table=/dev/had
首要修正该文件,增加新的引导内核:
image=/boot/bzImage-new
label=linux-new
root=/dev/hdb1
read-only
增加结束,该文件内容如下所示:
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
TImeout=50
image=/boot/bzImage-new
label=linux-new
root=/dev/hdb1
read-only
image=/boot/vmlinuz-2.2.5-15
label=linux
root=/dev/hdb1
read-only
other=/dev/hda1
label=dos
table=/dev/hda
这样,新的内核映象bzImage-new成为缺省的引导内核。
为了运用新的lilo.conf装备文件,还应履行下面的指令:
#cp /usr/src/linux/arch/i386/boot/zImage /boot/bzImage-new
其次装备lilo:
# /sbin/lilo
现在,当从头引导体系时,在boot:提示符后边有三种挑选:linux-new 、linux、dos,新内核成为缺省的引导内核。
至此,新的Linux内核现已树立,新增加的体系调用已成为操作体系的一部分,从头发动Linux,用户就能够在运用程序中运用该体系调用了。
(5)运用新的体系调用
在运用程序中运用新增加的体系调用mycall。相同为试验意图,咱们写了一个简略的比如xtdy.c。
#include
_syscall1(int,mycall,int,ret)
main()
{
printf(“%d n”,mycall(100));
}
编译该程序:
# cc -o xtdy xtdy.c
履行:
# xtdy
成果:
# 100
留意,因为运用了体系调用,编译和履行程序时,用户都应该是超级用户身份
http://blog.chinaunix.net/u2/62213/showart_488383.html
linux 增加体系调用
一.源码修正
1下载一个与所用体系内核版别挨近的内核,放在/usr/src下,解压,作个链接ln -s linux-2.6.18.1 linux
2修正:修正三个当地
1)/usr/src/linux/kerner/sys.c中增加,
asmlinkage int sys_mysyscall(int a)
{
return a;
}
2)界说体系调用号,/usr/src/linux/include/asm-i386/unistd.h
#define _NR_sysmycall 318 //不能与前面已有的重复
#define _NR_syscalls 319//修正体系中所用体系调用数目
3)在体系调用向量表里增加自界说的体系调用函数进口方位,
/usr/src/linux/arch/i386/kernel/syscall_table.S,曾经老版别是entry.s
.long sys_mysyscall
二、内核编译
1.在/boot下仿制装备文件,到/usr/src/linux下,改名位config,make menuconfig,能够不必修正,直接退出
2.make clean 清空曾经的编译痕迹
3.make,编译出来的是bzImage
4.make modules,make modules-install//编译、装置config里装备的模块
如不履行次过程,关于有的体系,制造不了initrd文件。体系就发动不了
5.假如直接make install,体系会主动制造initrd文件,并仿制initrd和bzimage文件到/boot下,修正grub.conf文件,重启体系,挑选进入新内核
6.不运用make install指令。仿制bzImage到/boot下,改名位vmlinuz-2.6.18.1,手艺制造initrd文件,/mkinitrd initrd-2.6.18.1.img 2.6.18.1,initrd文件名位initrd-2.6.18.1
7.修正grub.conf文件,仿制本来已有的发动设置,把TItle和kernel和initrd改名为新制造的即可
三、编写代码测验
int main(void)
{
int a=syscall(318,100);//318是体系调用号,100是参数
printf(“%d\n”,a);
return 0;
}
syscall是内核供给为用户程序的一个函数,
假如不运用syscall函数,也能够运用宏界说,可是在2.6.20今后的版别里,没有宏界说,需求自己从其他版别里仿制过来增加。