用gcc的-E选项来查看宏展开

有时代码中的宏挺复杂的, 人工去展开, 太费劲. 为了看复杂的宏 展开后的样子, 可以利用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 */

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值