Linux Kernel代码艺术——系统调用宏定义
我们习惯在SI(Source Insight)中阅读Linux内核,SI会建立符号表数据库,能非常方便地跳转到变量、宏、函数等的定义处。但在处理系统调用的函数时,却会遇到一些麻烦:我们知道系统调用函数名的特点是sys_×××,例如我们想找open函数的内核系统调用代码,在SI提供的符号表中搜索sys_open,能找到函数的声明:
asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);
原本SI提供从函数名按住Ctrl单击鼠标左键能跳转到定义处的功能,但运用在系统调用函数sys_open上却失败了,这是什么回事呢?
系统调用宏定义展开
经过分析,原来内核中系统调用采用了宏定义,如这里的sys_open就被定义为:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
可以猜测出这个宏定义展开之后就是上面函数声明那样的,难怪SI不能跳转到系统调用的定义处呢!
下面以open系统调用为例分析这个宏是如何展开的:
首先在 include/linux/syscall.h
中有下面这样的宏定义:
#define SYSCALL_DEFINE3(name, ...) \
SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
针对这个宏定义有几点说明:
- 反斜杠\:当宏定义过长需要换行时,在行尾要加上换行标志“\”;
- …:省略号代表可变的部分,下面用
__VA_AEGS__
代表省略的变长部分; - ##:分隔连接方式,它的作用是先分隔,然后进行强制连接,例如:
#define VAR(type, name) type name##_##type
VAR(int, var1);
展开之后就是:
int var1_int;
那么:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
展开之后是:
SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
这又是一个宏,根据宏定义:
#define SYSCALL_DEFINEx(x, sname, ...) \
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
展开为:
__SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
再根据宏定义:
#define __SYSCALL_DEFINEx(x, name, ...) \
asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__))
__SYSCALL_DEFINEx(3, _open, __VA_ARGS__)
展开为:
asmlinkage long sys_name(__SC_DECL3(__VA_ARGS__))
这里 __VA_ARGS__
是 const char __user *, filename, int, flags, umode_t, mode
,而同样__SC_DECL3
又是一组宏定义:
#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__)
这样,一步一步地展开:
__SC_DECL3(const char __user *, filename, int, flags, umode_t, mode)
==> __SC_DECL3(const char __user *, filename, int, flags, umode_t, mode)
==> const char __user* filename, __SC_DECL2( int, flags, umode_t, mode)
==> const char __user* filename, int flags, __SC_DECL1(umode_t, mode)
==> const char __user* filename, int flags, umode_t mode
最终:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
宏定义展开之后就成为:
asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);
正如我们之前猜测的那样。
相关推荐
choupiaoyi 2020-04-19
zuixin 2020-02-22
Joymine 2020-01-01
lvbin0 2012-07-03
Will0 2011-03-15
fengjing81 2019-11-07
liangds 2011-10-03
ericasadun 2012-01-04
wwater 2011-11-20
liangds 2012-06-03
mojianc 2019-06-27
87214551 2013-06-13
小南地带 2019-06-21
tubiebutu 2019-06-21
tubiebutu 2019-06-20
shi0 2011-09-29
fzhykx 2018-08-16