系统调用(二)
SYSCALL_DEFINEx函数调用
文件syscall.h
在include/linux/中.
在select和epoll的分析中, 出现了好几次SYSCALL_DEFINEx()
的函数, 这些究竟是些什么呢? 现在我们就来探讨一下源码中他们是什么.
#define SYSCALL_DEFINE0(name) asmlinkage long sys_##name(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, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
看了这几个宏定义, 在结合我们传入参数的个数, 大致也能想到x是代表传入参数的值.(如果对define的#, ## 符号的操作不了解, 可以先看下这篇)
#define SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__)); \
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__)); \
asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__)) \
{ \
__SC_TEST##x(__VA_ARGS__); \
return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__)); \
} \
SYSCALL_ALIAS(sys##name, SyS##name); \
static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))
这个函数宏定义看起来很不理解, 这里我们从后面开始看, 倒数第二排有一个SYSCALL_ALIAS(sys##name, SyS##name), 就是给sys##name取一个别名, 为SyS##name, 所以使用sys##name就相当调用SyS##name函数.
#ifdef CONFIG_PPC64
#define SYSCALL_ALIAS(alias, name) \
asm ("\t.globl " #alias "\n\t.set " #alias ", " #name "\n" \
"\t.globl ." #alias "\n\t.set ." #alias ", ." #name)
#else
#define SYSCALL_ALIAS(alias, name) \
asm ("\t.globl " #alias "\n\t.set " #alias ", " #name)
#endif
好了, 现在我们从
- 第一行开始看, 现在执行的SYSCALL_DEFINEx也就是确认执行上面的7个宏定义函数.
- 第二, 三行是函数的声明
- 第四行开始就是SyS##name 的函数定义了
- 最后一行是调用SYS##name 函数
__SC_DECL##x宏定义
我们再来看传入的参数.先来看参数__SC_DECL##x(__VA_ARGS__)
的宏定义
#define __SC_DECL1(t1, a1) t1 a1
#define __SC_DECL2(t2, a2, ...) t2 a2, __SC_DECL1(__VA_ARGS__)
#define __SC_DECL3(t3, a3, ...) t3 a3, __SC_DECL2(__VA_ARGS__)
#define __SC_DECL4(t4, a4, ...) t4 a4, __SC_DECL3(__VA_ARGS__)
#define __SC_DECL5(t5, a5, ...) t5 a5, __SC_DECL4(__VA_ARGS__)
#define __SC_DECL6(t6, a6, ...) t6 a6, __SC_DECL5(__VA_ARGS__)
可以看出来该宏定义就是一层一层的将参数展开. 这里我用一个select的函数做例子来解释
SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, fd_set __user *, exp, struct timeval __user *, tvp)
展开过程如下:
__SC_DECL5(int, n, fd_set user *, inp, fd_set user *, outp, fd_set user *, exp, struct timeval user *, tvp) ->
int n, __SC_DECL4(fd_set user *, inp, fd_set user *, outp, fd_set user *, exp, struct timeval user *, tvp) ->
int n, fd_set inp, __SC_DECL3(fd_set user *, outp, fd_set user *, exp, struct timeval __user *, tvp) ->
int n, fd_set inp, fd_set outp, __SC_DECL2(fd_set user *, outp, fd_set user *, exp, struct timeval __user *, tvp) ->
int n, fd_set inp, fd_set outp, fd_set exp, __SC_DECL1(truct timeval __user *, tvp) ->
int n, fd_set inp, fd_set outp, fd_set exp, struct timeval *, tvp
经过者一系列的转化, 终于将我们所有的参数都提取出来了.
同样的, 调用long SyS##name(__SC_LONG##x(__VA_ARGS__))
也是一步一步的展开, 但是有一点不一样, 该调用会把参数都强行转化为long类型. 是因为不转为long类型, 会有一定的漏洞. 具体漏洞有兴趣的可以去查CVE-2009-2009.
#define __SC_LONG1(t1, a1) long a1
#define __SC_LONG2(t2, a2, ...) long a2, __SC_LONG1(__VA_ARGS__)
#define __SC_LONG3(t3, a3, ...) long a3, __SC_LONG2(__VA_ARGS__)
#define __SC_LONG4(t4, a4, ...) long a4, __SC_LONG3(__VA_ARGS__)
#define __SC_LONG5(t5, a5, ...) long a5, __SC_LONG4(__VA_ARGS__)
#define __SC_LONG6(t6, a6, ...) long a6, __SC_LONG5(__VA_ARGS__)
#define __SC_CAST1(t1, a1) (t1) a1
#define __SC_CAST2(t2, a2, ...) (t2) a2, __SC_CAST1(__VA_ARGS__)
#define __SC_CAST3(t3, a3, ...) (t3) a3, __SC_CAST2(__VA_ARGS__)
#define __SC_CAST4(t4, a4, ...) (t4) a4, __SC_CAST3(__VA_ARGS__)
#define __SC_CAST5(t5, a5, ...) (t5) a5, __SC_CAST4(__VA_ARGS__)
#define __SC_CAST6(t6, a6, ...) (t6) a6, __SC_CAST5(__VA_ARGS__)
#define __SC_TEST(type) BUILD_BUG_ON(sizeof(type) > sizeof(long))
#define __SC_TEST1(t1, a1) __SC_TEST(t1)
#define __SC_TEST2(t2, a2, ...) __SC_TEST(t2); __SC_TEST1(__VA_ARGS__)
#define __SC_TEST3(t3, a3, ...) __SC_TEST(t3); __SC_TEST2(__VA_ARGS__)
#define __SC_TEST4(t4, a4, ...) __SC_TEST(t4); __SC_TEST3(__VA_ARGS__)
#define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__)
#define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__)
总结
其实具体的宏定义流程还是很容易看懂的, 就只是体会到了宏定义的用法. 每个参数的读出都是一环叩一环的, 对于define的运用, 自己还要区总结一下, 然后在来重新为这篇加上几句. 看到这个源码我也明白为什么系统调用的参数不能超过6个, 毕竟宏定义也就只设置了6个, 也发现文件的函数也没有声明超过6个参数的函数, 同时通用寄存器也是6个, 每个寄存器存放一个数据. 不过不代表参数不能超过6个, 毕竟还可以用栈来传递参数, 这里只是说系统调用的函数, 大概收获的也就是这些吧.