系统调用的封装

来源:互联网 发布:傲游便携优化版 编辑:程序博客网 时间:2024/06/11 04:56

封装系统调用是一件简单而枯燥的事情

封装系统调用的基本过程是:
1. 确认要封装的系统调用,并将系统调用对应的系统调用名称设置为函数的名称。
如系统调用号1对应的系统调用exit封装的函数的名字便是exit。
2. 确认要封装的系统调用的参数及参数类型,并设置为函数的参数。
如exit系统调用的参数为int status,则exit函数参数为int status, exit(int status)。
3. 确认要封装的系统调用的返回值类型,并设置函数的返回值。
如exit系统调用的返回值类型为int,则exit函数返回值为int,int exit(int status)。

完成以上内容,一个函数的基本框架已经搭建完成。

系统调用1->exit封装后int exit(int status){}

还缺少函数的执行单元,执行单元可以使用嵌入式汇编完成。

int exit(int status){    long __res;    asm("int $0x80"           : "=a" (__res)           : "0" (1),"b" ((long)(status)));       if (__res >= 0)               return (int) __res;       errno = -__res; \      return -1; \}   

通过以上步骤便可以完成任意系统调用的封装。

使用宏,封装变得方便许多

linux内核中提供了一种使用宏来封装系统调用的方式。

宏的使用主要在2个方面。

  1. 定义系统调用号与系统调用名称之间的关系。
#define __NR_restart_syscall 0#define __NR_exit 1#define __NR_fork 2#define __NR_read 3...
  1. 完成函数的构建。
#define _syscall0(type,name) \type name(void) \{ \long __res; \__asm__ volatile ("int $0x80" \    : "=a" (__res) \    : "0" (__NR_##name)); \if (__res >= 0) \    return (type) __res; \ex_errno = -__res; \return -1; \}#define _syscall1(type,name,type1,arg1) \type name(type1 arg1) \{ \long __res; \__asm__ volatile ("int $0x80" \    : "=a" (__res) \    : "0" (__NR_##name),"b" ((long)(arg1))); \if (__res >= 0) \    return (type) __res; \ex_errno = -__res; \return -1; \}...

以_syscall1(type,name,type1,arg1) 为例。
exit系统调用可以写成_syscall1(int,exit,int,status)。而其宏展开后为

int exit(int status) \{ \long __res; \__asm__ volatile ("int $0x80" \    : "=a" (__res) \    : "0" (1),"b" ((long)(status))); \if (__res >= 0) \    return (int) __res; \errno = -__res; \return -1; \}所有type被第一个宏参数int替换了,所有的name被第二个宏参数exit替换了。所有的type1被第三个宏参数int替换了。所有的arg1被第四个宏参数status替换了。还有重要的一点  __NR_##name中 ##name表示##name会被修改成name表示的字符串,当name为exit时,__NR_##name为__NR_exit,__NR_exit将被替换为上面定义的宏__NR_exit对应的值。

替换后一个exit函数也建立起来了。

使用这种宏定义可以快速的构建起系统调用。

附录

32位系统linux所支持的系统调用列表

32位系统linux封装系统调用宏

0 0
原创粉丝点击