[关闭]
@Aklis 2016-10-24T17:03:47.000000Z 字数 2198 阅读 355

Add system call for linux

系统调用, Linux, compile, syscall


  1. 系统调用的实现(确保程序被编译进内核)
  2. 新的系统调用程序入口点(进行系统调用的入口)
  3. 新的系统调用号(程序从用户态到内核态所需要的入口)

在linux中,系统调用是用户空间访问内核的一种手段,除异常和中断外,他们是进入内核的合法入口。系统调用的数量很少,在i386上只有大概300个左右。
应用程序员通过C库中的应用程序接口(API)而不是直接通过系统调用来编程。 调用链:APP --> LIB --> kernel
(syscall) --> module --> hardware

应用程序调用C库中的函数---> C库中的函数通过int 80 进入内核态,同时传递系统调用号给内核 ---> 中断处理程序system_call ---> sys_call_table(进入系统调用服务例程,执行完毕后返回例程) ---> 中断处理程序完毕后回到用户态

C库中的函数可以不调用系统调用,也可以只是简单封装一个系统调用,还可以通过调用多个系统调用来实现一个功能。 linux
本身提供的一组宏来对系统调用直接进行访问。man 2 syscall。
从程序员的角度来看,系统调用无关紧要,他们只需要跟API打交道就可以了;
从内核的角度来看,内核只跟系统调用打交道,库函数及应用程序怎么使用系统调用不是内核所关心的。

用户态程序调用syscall:

  1. #include <linux/unistd.h>
  2. #include <sys/syscall.h>
  3. # define __NR_mysyscall 326
  4. int main()
  5. {
  6. syscall(__NR_mysyscall);
  7. }

响应系统调用号,会在syscall_table中找到对应的系统调用服务例程。

0x00 确定新的调用号

arch/x86/entry/syscalls/syscall_64.tbl

添加新的系统调用号

  1. ...
  2. 326 64 aksyscall sys_aksyscall
  3. ...

.tbl文件之后被作为模版生成头文件,但输出的头文件是哪个我还没验证。
我所知道的是int 80所传递过来的系统调用号就一定是这个文件里面定义的。

至于syscall_32.tbl里面的先不管了。。

0x01 实现与声明

编写好对应的程序入口(entry point)(也就是系统调用的实现,一般存在于kernel/xx.ck中)
你创建的新的系统调用abc()都会被命名成sys_abc().

如果在Kconfig里面有定义编译选项的话,就把新的源文件编译进内核,如果不想在Kconfig的话,直接写在一定会被编译进内核的文件内,也就是搭便车,比如写在sys.c文件里面。

在新的linux版本中,都用一类宏SYSCALL_DEFINEn()来声明,不需要你明确声明。
'n' 就是新的系统调用的参数的个数。

展开宏的代码在include/linux/syscalls.h中,Aklis颤抖不已。

比如这一次添加的系统调用是

SYSCALL_DEFINE3(func_name, type1, name1, type2, name2, type3, name3)

就会变成

0x02 分配系统调用号

一个新的(系统调用)程序入口需要一个一致的函数类型,先在 include/linux/syscalls.h (系统调用声明文件) 里面声明,创建一个asmlinkage去匹配被调用的系统调用。早期的声明方法:

asmlinkage long sys_abc(...);

一些架构有自己的系统调用表,但有多个架构共享一个通用的系统调用表
可以直接把你的系统调用添加到通用表。

直接在include/uapi/asm-generic/unistd.h 系统调用号表
添加

  1. #define __NR_abc 233
  2. __SYSCALL(__NR_abc, sys_abc)

写上这个就不需要自己写asmlinkage

0x03 回调实现

同时更新系统调用号去关联新增的系统调用入口。
除此之外,还要注意如果多个新的系统调用被添加到同样的窗口(merge window),
你的新的系统调用号可能需要调整,防止冲突。

kernel/sys_ni.c
在这些添加你的系统调用。
cond_syscall(sys_abc);

0xFF

讲道理你添加了一个新的功能或者系统调用,就应该在 Kconfig 那里添加一个选项以便编译的时候选择开不开。

0xAK 一些问题

关于tbl文件*

common 是不是包括了x86_64与i386
那么syscall_64.tbl和syscall_32.tbl
又为什么需要特地分出来。

这两个文件都存在于arch/x86下

关于叫法*

unistd.h 系统调用号 表
syscalls.h 系统调用声明 表
都叫syscall table我很困扰啊。
还有个arch/x86/entry/syscalls/syscall_64.tbl……

错误 :mdadm: /etc/mdadm/mdadm.conf defines no arrays.
解决方案:
step 1 : /usr/share/mdadm/mkconf > /etc/mdadm/mdadm.conf
step 2 : update-initramfs -u
step 3 : reboot

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注