当前位置:   article > 正文

【linux kernel】linux内核中的系统调用分析_syscall_define1

syscall_define1

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/iriczhao/article/details/122420525


linux内核中的系统调用


注:本文章所有源代码出自linux kernel,版本:4.1.15

一、简介

​ 系统调用在内核中的入口都是sys_xxx,在linux内核中的系统调用由SYSCALL_DEFINE宏来定义。该宏定义在(include/linux/syscalls.h)文件中,如下:

#define SYSCALL_DEFINE0(sname)					\
	SYSCALL_METADATA(_##sname, 0);				\
	asmlinkage long sys_##sname(void)

#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)

#define SYSCALL_DEFINEx(x, sname, ...)				\
	SYSCALL_METADATA(sname, x, __VA_ARGS__)			\
	__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)					\
	asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))	\
		__attribute__((alias(__stringify(SyS##name))));		\
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));	\
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
	{								\
		long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));	\
		__MAP(x,__SC_TEST,__VA_ARGS__);				\
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
		return ret;						\
	}								\
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

__VA_ARGS__代表宏定义中(…)参数。

SYSCALL_METADATA宏定义由CONFIG_FTRACE_SYSCALLS宏管控,如果没有定义CONFIG_FTRACE_SYSCALLS,那么SYSCALL_METADATA将没有替换内容。

二、【SYSCALL_DEFINE0】定义无参数的系统调用

对于无参数的系统调用,将使用SYSCALL_DEFINE0宏进行函数声明,例如sys_fork

asmlinkage long sys_fork(void);
  • 1

sys_fork定义出自(kernel/fork.c)文件:

SYSCALL_DEFINE0(fork)
{
#ifdef CONFIG_MMU
	return do_fork(SIGCHLD, 0, 0, NULL, NULL);
#else
	/* can not support in nommu mode */
	return -EINVAL;
#endif
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
三、【SYSCALL_DEFINEx】定义有参数的系统调用

对于含有参数的系统调用,该宏定义将替换__SYSCALL_DEFINEx(x,name,...)

#define __SYSCALL_DEFINEx(x, name, ...)					\
	asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))	\
		__attribute__((alias(__stringify(SyS##name))));		\
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));	\
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
	{								\
		long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));	\
		__MAP(x,__SC_TEST,__VA_ARGS__);				\
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
		return ret;						\
	}								\
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
四、SYSCALL_DEFINEx详细分析

本文以socket为例,socket系统调用含有三个参数,声明如下:

asmlinkage long sys_socket(int, int, int);
  • 1

由于含有3个函数参数,故将使用宏SYSCALL_DEFINE3进行定义,如下代码(/net/socket.c):

SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
	int retval;
	struct socket *sock;
	int flags;

	BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);
	BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);
	BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);
	BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);

	flags = type & ~SOCK_TYPE_MASK;
	if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
		return -EINVAL;
	type &= SOCK_TYPE_MASK;

	if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK))
		flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK;

	retval = sock_create(family, type, protocol, &sock);
	if (retval < 0)
		goto out;

	retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
	if (retval < 0)
		goto out_release;

out:
	return retval;

out_release:
	sock_release(sock);
	return retval;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

如果将SYSCALL_DEFINE3进行替换后,将得到以下代码片段:

asmlinkage long sys_socket(__MAP(x,__SC_DECL,__VA_ARGS__))	__attribute__((alias(__stringify(SyS##name))));
static inline long SYSC_socket(__MAP(x,__SC_DECL,__VA_ARGS__));
asmlinkage long SyS_socket(__MAP(x,__SC_LONG,__VA_ARGS__));
asmlinkage long SyS_socket(__MAP(x,__SC_LONG,__VA_ARGS__))	\
{								\
		long ret = SYSC_socket(__MAP(x,__SC_CAST,__VA_ARGS__));	\
		__MAP(x,__SC_TEST,__VA_ARGS__);				\
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
		return ret;						\
}
static inline long SYSC_socket(__MAP(x,__SC_DECL,__VA_ARGS__))
{
        int retval;
        struct socket *sock;
        int flags;

 		//省略
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

1、上述代码中,一直出现__MAP这个宏,如下代码(include/linux/syscalls.h):

#define __MAP0(m,...)
#define __MAP1(m,t,a) m(t,a)
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
#define __MAP(n,...) __MAP##n(__VA_ARGS__)//该宏用于其他地方
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

2、__SC_DECL这个宏,如下定义(include/linux/syscalls.h):

#define __SC_DECL(t, a)	t a
  • 1

3、__SC_CAST这个宏,如下定义(include/linux/syscalls.h):

#define __SC_CAST(t, a)	(t) a
  • 1

4、__SC_TEST这个宏,如下定义(include/linux/syscalls.h):

#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))
  • 1

5、__PROTECT这个宏,如下定义:

#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)

//该宏定义出自(include/linux/linkage.h)文件
# define asmlinkage_protect(n, ret, args...)	do { } while (0)
  • 1
  • 2
  • 3
  • 4

最后,经过层层宏替换,SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)将变成如下所示的代码:

asmlinkage long sys_socket(__MAP(x,__SC_DECL,__VA_ARGS__))	__attribute__((alias("SyS_socket"))));
static inline long SYSC_socket(__MAP(x,__SC_DECL,__VA_ARGS__));
asmlinkage long SyS_socket(__MAP(x,__SC_LONG,__VA_ARGS__));
asmlinkage long SyS_socket(__MAP(x,__SC_LONG,__VA_ARGS__))	\
{								\
		long ret = SYSC_socket(__MAP(x,__SC_CAST,__VA_ARGS__));	\
		__MAP3(__SC_TEST,__VA_ARGS__);				\
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
		return ret;						\
}


static inline long SYSC_socket(int family,int type,int protocol)
{
        int retval;
        struct socket *sock;
        int flags;

 		//省略
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

到这先打住,绕啊绕,好似陷入迷雾深处,实则上述代码中SYSC_socket()SyS_socket()函数经过层层宏替换后,本质上是:

asmlinkage long sys_socket(int family, int type, int protocol)
{
        int retval;
        struct socket *sock;
        int flags;

 		//省略
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

​ 上述系统调用机制的实现,还依赖于C语言的alias属性,alias属性的功能是给符号起一个别名,因此两个名字用起来就会是一样的效果。

​ 因此asmlinkage long sys_socket(__MAP(x,__SC_DECL,__VA_ARGS__)) __attribute__((alias("SyS_socket"))));这行代码的用意就在于此。


【站在巨人的肩膀上】
(1)Linux系统调用之SYSCALL_DEFINE
https://blog.csdn.net/hxmhyp/article/details/22699669

(2)linux内核之chdir分析
https://blog.csdn.net/sanwenyublog/article/details/50850469

(3)Linux下系统调用的三种方法
https://www.linuxidc.com/Linux/2014-12/110238.htm

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/214590
推荐阅读
相关标签
  

闽ICP备14008679号