您的位置:首页 > 其它

系统调用的封装

2016-02-28 11:24 197 查看
封装系统调用是一件简单而枯燥的事情

封装系统调用的基本过程是:

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个方面。

定义系统调用号与系统调用名称之间的关系。

#define __NR_restart_syscall 0
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
...


完成函数的构建。

#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封装系统调用宏
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: