有时代码中的宏挺复杂的, 人工去展开, 太费劲. 为了看复杂的宏 展开后的样子, 可以利用gcc -E选项来帮我们展开.
gcc -E选项的作用: 仅预编译
-E选项就是只做预编译处理, 不做编译, 汇编, 链接.
$ gcc --help
Usage: gcc [options] file...
Options:
...
...
-v Display the programs invoked by the compiler.
-### Like -v but options quoted and commands not executed.
-E Preprocess only; do not compile, assemble or link.
-S Compile only; do not assemble or link.
-c Compile and assemble, but do not link.
-o <file> Place the output into <file>.
...
...
举例
比如要对, 系统调用open定义进行宏展开:
/* in file fs/open.c */
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
而 SYSCALL_DEFINE3定义在 include/linux/syscalls.h 中
/* in file: include/linux/syscalls.h */
#define SYSCALL_METADATA(sname, nb, ...) \
static const char *types_##sname[] = { \
__MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \
}; \
static const char *args_##sname[] = { \
__MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \
}; \
SYSCALL_TRACE_ENTER_EVENT(sname); \
SYSCALL_TRACE_EXIT_EVENT(sname); \
static struct syscall_metadata __used \
__syscall_meta_##sname = { \
.name = "sys"#sname, \
.syscall_nr = -1, /* Filled in at boot */ \
.nb_args = nb, \
.types = nb ? types_##sname : NULL, \
.args = nb ? args_##sname : NULL, \
.enter_event = &event_enter_##sname, \
.exit_event = &event_exit_##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
}; \
static struct syscall_metadata __used \
__attribute__((section("__syscalls_metadata"))) \
*__p_syscall_meta_##sname = &__syscall_meta_##sname;
#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__))
为了看 SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) {…} 究竟是什么样的, 可以这么干:
写个c文件, 包含上述内容:
$ cat foo.c
#define SYSCALL_METADATA(sname, nb, ...) \
static const char *types_##sname[] = { \
__MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \
}; \
static const char *args_##sname[] = { \
__MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \
}; \
SYSCALL_TRACE_ENTER_EVENT(sname); \
SYSCALL_TRACE_EXIT_EVENT(sname); \
static struct syscall_metadata __used \
__syscall_meta_##sname = { \
.name = "sys"#sname, \
.syscall_nr = -1, /* Filled in at boot */ \
.nb_args = nb, \
.types = nb ? types_##sname : NULL, \
.args = nb ? args_##sname : NULL, \
.enter_event = &event_enter_##sname, \
.exit_event = &event_exit_##sname, \
.enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \
}; \
static struct syscall_metadata __used \
__attribute__((section("__syscalls_metadata"))) \
*__p_syscall_meta_##sname = &__syscall_meta_##sname;
#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__))
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
然后对foo.c用gcc -E来操作, 可以直接输出到标准输出, 也可以输出到文件
## 输出到文件, 可以用gcc的-o选项,
$ gcc -E foo.c -o foo.cpp
$
$ cat foo.cpp
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"
# 63 "foo.c"
static const char *types__open[] = { __MAP(3,__SC_STR_TDECL,const char __user *, filename, int, flags, umode_t, mode) }; static const char *args__open[] = { __MAP(3,__SC_STR_ADECL,const char __user *, filename, int, flags, umode_t, mode) }; SYSCALL_TRACE_ENTER_EVENT(_open); SYSCALL_TRACE_EXIT_EVENT(_open); static struct syscall_metadata __used __syscall_meta__open = { .name = "sys""_open", .syscall_nr = -1, .nb_args = 3, .types = 3 ? types__open : NULL, .args = 3 ? args__open : NULL, .enter_event = &event_enter__open, .exit_event = &event_exit__open, .enter_fields = LIST_HEAD_INIT(__syscall_meta__open.enter_fields), }; static struct syscall_metadata __used __attribute__((section("__syscalls_metadata"))) *__p_syscall_meta__open = &__syscall_meta__open; asmlinkage long sys_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode)) __attribute__((alias(__stringify(SyS_open)))); static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode)); asmlinkage long SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode)); asmlinkage long SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode)) { long ret = SYSC_open(__MAP(3,__SC_CAST,const char __user *, filename, int, flags, umode_t, mode)); __MAP(3,__SC_TEST,const char __user *, filename, int, flags, umode_t, mode); asmlinkage_protect(3, ret,__MAP(3,__SC_ARGS,const char __user *, filename, int, flags, umode_t, mode)); return ret; } static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode))
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
## 直接输出到标准输出:
$ gcc -E foo.c
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"
# 63 "foo.c"
static const char *types__open[] = { __MAP(3,__SC_STR_TDECL,const char __user *, filename, int, flags, umode_t, mode) }; static const char *args__open[] = { __MAP(3,__SC_STR_ADECL,const char __user *, filename, int, flags, umode_t, mode) }; SYSCALL_TRACE_ENTER_EVENT(_open); SYSCALL_TRACE_EXIT_EVENT(_open); static struct syscall_metadata __used __syscall_meta__open = { .name = "sys""_open", .syscall_nr = -1, .nb_args = 3, .types = 3 ? types__open : NULL, .args = 3 ? args__open : NULL, .enter_event = &event_enter__open, .exit_event = &event_exit__open, .enter_fields = LIST_HEAD_INIT(__syscall_meta__open.enter_fields), }; static struct syscall_metadata __used __attribute__((section("__syscalls_metadata"))) *__p_syscall_meta__open = &__syscall_meta__open; asmlinkage long sys_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode)) __attribute__((alias(__stringify(SyS_open)))); static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode)); asmlinkage long SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode)); asmlinkage long SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode)) { long ret = SYSC_open(__MAP(3,__SC_CAST,const char __user *, filename, int, flags, umode_t, mode)); __MAP(3,__SC_TEST,const char __user *, filename, int, flags, umode_t, mode); asmlinkage_protect(3, ret,__MAP(3,__SC_ARGS,const char __user *, filename, int, flags, umode_t, mode)); return ret; } static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode))
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
由于输出的格式没有自动缩进与对齐, 不太好看, 可以将其缩进对齐后, 在查看:
$ cp foo.cpp indent_foo.c
$ vim indent_foo.c # 将其缩进并对齐
$ cat indent_foo.c
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 31 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 32 "<command-line>" 2
# 1 "foo.c"
# 63 "foo.c"
static const char *types__open[] = {
__MAP(3,__SC_STR_TDECL,const char __user *, filename, int, flags, umode_t, mode)
};
static const char *args__open[] = {
__MAP(3,__SC_STR_ADECL,const char __user *, filename, int, flags, umode_t, mode)
};
SYSCALL_TRACE_ENTER_EVENT(_open);
SYSCALL_TRACE_EXIT_EVENT(_open);
static struct syscall_metadata __used __syscall_meta__open = {
.name = "sys""_open",
.syscall_nr = -1,
.nb_args = 3,
.types = 3 ? types__open : NULL,
.args = 3 ? args__open : NULL,
.enter_event = &event_enter__open,
.exit_event = &event_exit__open,
.enter_fields = LIST_HEAD_INIT(__syscall_meta__open.enter_fields),
};
static struct syscall_metadata
__used __attribute__((section("__syscalls_metadata")))
*__p_syscall_meta__open = &__syscall_meta__open;
asmlinkage long
sys_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode))
__attribute__((alias(__stringify(SyS_open))));
static inline long
SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode));
asmlinkage long
SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode));
asmlinkage long
SyS_open(__MAP(3,__SC_LONG,const char __user *, filename, int, flags, umode_t, mode))
{
long ret = SYSC_open(__MAP(3,__SC_CAST,const char __user *, filename, int, flags, umode_t, mode));
__MAP(3,__SC_TEST,const char __user *, filename, int, flags, umode_t, mode);
asmlinkage_protect(3, ret,__MAP(3,__SC_ARGS,const char __user *, filename, int, flags, umode_t, mode));
return ret;
}
static inline long SYSC_open(__MAP(3,__SC_DECL,const char __user *, filename, int, flags, umode_t, mode))
{
if (force_o_largefile())
flags |= O_LARGEFILE;
return do_sys_open(AT_FDCWD, filename, flags, mode);
}
由上述可见:
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) {…}
展开后的样子是SYSC_open() (当然这还并没有最终彻底完全展开, 但已经可以看出open函数代码实际的样子了)
并在SYSC_open()定义之前, 做了很多额外的操作
open系统调用, 最后其实是 SYSC_open()函数.
而SYSC_open()被SyS_open()调用, 而SyS_open()是sys_open的别名.
即, open系统调用, 实际是
sys_open() == SyS_open() --> SYSC_open() --> do_sys_open().
问题
怎么让gcc -E输出, 自动缩进对齐?
关于这个, 涉及到 “自动统一格式化代码风格” 工具, 可以试试indent工具
$ sudo apt-get install indent
然后, 执行
$ indent -npro -kr -i8 -ts8 -sob -l80 -ss -bl -bli 0 foo.cpp -o _foo.cpp
关于 代码风格格式化工具, 请参考:
/* TODO */