系统调用定义宏 SYSCALL_DEFINEx 的分析

了解系统调用的同学应该知道, 系统调用在内核中的入口都是sys_xxx, 比如read()系统调用在内核的入口就是sys_read(). 但查看内核源码会发现, 内核中并没有sys_xxx()这样的函数, 根本就无法搜到sys_xxx()函数的定义与实现.

其实, Linux内核中的系统调用, 都是经过一个叫SYSCALL_DEFINEx的宏展开出来的, 没展开之前, 是无法搜到sys_xxx()的.

本文就是分析定义系统调用的宏SYSCALL_DEFINEx的实现.

这里以open()这个系统调用为例, 一步步的分析, 看看SYSCALL_DEFINEx宏如何定义出一个系统调用的函数(头).

本文所描述的内核源码是kernel 4.0版本的.

1 系统调用的定义在源码中能直接看到的样子

对于xxx()系统调用, 可以先man 2 xxx看下它的API原型, 假设是

return_type  xxx(type1 arg1,  type2 arg2, ..., typex argx);
/* xxx()系统调用的返回值类型是return_type. 
 * xxx()系统调用有x个参数.
 * /

则在内核源码中, 只能看到这样的, 不直观的xxx系统调用的定义:

SYSCALL_DEFINEx(xxx, type1, arg1, type2, arg2, ..., typex, argx)
{
    /* 函数体(函数的具体实现) */
}

2 如何搜索内核源码中, 系统调用定义的地方?

根据上述说明, 可以在内核源码中, 搜索xxx()时这么grep

cd ${KERNEL_CODE_BASE}            #切换到内核源码根目录
grep -rn  "SYSCALL_DEFINEx(xxx,"   #SYSCALL_DEFINEx中的x换成实际的参数个数

例如, 以本文的open()为例, 它三个参数, 那么这么搜

$ grep -rn "SYSCALL_DEFINE3(open,"
fs/compat.c:1090:COMPAT_SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
fs/open.c:1026:SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

可以知道, open()定义的地方在fs/open.c的1026行.
fs/compat.c不考虑了, 那个是为了兼容用的.

3 SYSCALL_DFEINEx() {…} 宏的分析

在"fs/open.c"中可以找到这个, 它就是open系统调用的定义.
SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)

/* filename: 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()宏有多个参数, 仔细看看, 会知道, 它们是函数名, 及 "类型名, 参数名"的对(pair), 在man 2 open中, 可以看到open()的原型

int open(const char *pathname, int flags, mode_t mode);

然后去找SYSCALL_DEFINE3宏 定义的地方, 很容易搜到在"include/linux/syscalls.h"中

/* filename:  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__)

可以知道, 想看定义open的SYSCALL_DEFINE3是啥样的, 需要看SYSCALL_DEFINEx是啥样的
首先 ##是连接符,__VA_ARGS__代表前面…里面的可变参数

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

为了看宏展开的样子, 其实不用人手工去去一个个的替换, gcc提供了工具, 就是用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>.
  ...
  ...

因此, 可以写个c文件:

$ cat foo.c

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __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"




SYSCALL_DEFINEx(3, _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);
}

## 直接输出到标准输出:
$ 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"




SYSCALL_DEFINEx(3, _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);
}


为了去掉预处理后的文件中的这些东西, 可以加-P参数

// 为了去掉以下这些#开头的信息, (这些叫linemarkers), 可以给gcc传-P参数
# 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"
## man  gcc中搜索-P

       -P  Inhibit generation of linemarkers in the output from the preprocessor.  This might be useful when
           running the preprocessor on something that is not C code, and will be sent to a program which might be
           confused by the linemarkers.

为了方便查看系统调用open展开的过程, 本文采取的描述方式是, 每次展开一步, 而不是一下子全展开.

3.2 展开SYSCALL_DEFINE3

按照3.1节的方法, 展开SYSCALL_DEFINE3:

演示如下:

$ cat foo.c

#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __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);
}


$ gcc -E -P foo.c -o foo.cpp
$ cat foo.cpp
SYSCALL_DEFINEx(3, _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);
}
$

可以看到, 不再有很多linemarkers 信息了

3.3 展开宏SYSCALL_DEFINEx

上面将SYSCALL_DEFINE3展开为SYSCALL_DEFINEx了, 下面就是继续展开SYSCALL_DEFINEx

在foo.cpp的基础上, 继续添加SYSCALL_DEFINEx的宏定义, 然后继续用gcc -E -P来展开

$ cat foo.cpp > 2foo.c
$ vim 2foo.c
$ cat 2foo.c

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

SYSCALL_DEFINEx(3, _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);
}
$ gcc -E -P 2foo.c -o 2foo.cpp
$ cat 2foo.cpp
SYSCALL_METADATA(_open, 3, const char __user *, filename, int, flags, umode_t, mode) __SYSCALL_DEFINEx(3, _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);
}
$

3.4 展开宏 __SYSCALL_DEFINEx

还是按照每次展开一步的原则, 继续展开__SYSCALL_DEFINEx, 这里添加__SYSCALL_DEFINEx的宏定义:

$ cat 2foo.cpp  > 3foo.c
$ vim 3foo.c
$ gcc -E -P 3foo.c -o 3foo.cpp
$ cat 3foo.cpp
SYSCALL_METADATA(_open, 3, const char __user *, filename, int, flags, umode_t, mode) 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); __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);
}
$

上述展开后, 发现格式不好看, 这里用内核代码中提供的Lindent脚本(参考链接: )来格式化它.
Lindent脚本其实是调用indent工具, 给indent传入一些格式化的选项.

# 拷贝内核源码提供的Lindent脚本, 它可以用来格式化代码的风格
$ cp /path/to/kernel_code/scripts/Lindent .
$ ls
2foo.c  2foo.cpp  3foo.c  3foo.cpp  foo.c  foo.cpp  Lindent

# Lindent脚本实际是调用indent工具
$ cat Lindent
#!/bin/sh
PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
RES=`indent --version`
V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1`
V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2`
V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3`
if [ $V1 -gt 2 ]; then
  PARAM="$PARAM -il0"
elif [ $V1 -eq 2 ]; then
  if [ $V2 -gt 2 ]; then
    PARAM="$PARAM -il0";
  elif [ $V2 -eq 2 ]; then
    if [ $V3 -ge 10 ]; then
      PARAM="$PARAM -il0"
    fi
  fi
fi
indent $PARAM "$@"
$

# indent的工具简要的用法如下
$ indent --help
usage: indent file [-o outfile ] [ options ]
       indent file1 file2 ... fileN [ options ]
# 用Lindent来格式化刚才生成的, 格式难看的3foo.cpp, 为了防止覆盖3foo.cpp, 
# 我们指定-o参数, 让格式化后的代码输出到一个新文件中
$ ./Lindent 3foo.cpp -o _3foo.cpp
me@ukylin:~/workplace/code/test/0916$ ls
2foo.c  2foo.cpp  3foo.c  _3foo.cpp  3foo.cpp  foo.c  foo.cpp  Lindent

# 查看格式化后的_3foo.cpp, 也就是foo.c展开后的样子.
$ cat _3foo.cpp
SYSCALL_METADATA(_open, 3, const char __user *, filename, int, flags, umode_t,
                 mode)
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);
        __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);
}
$

3.5 展开SYSCALL_METADATA

下一步, 展开SYSCALL_METADATA,

$ cat _3foo.cpp > 4foo.c
## 添加 SYSCALL_METADATA的宏定义
$ vim 4foo.c
$ ls
2foo.c  2foo.cpp  3foo.c  _3foo.cpp  3foo.cpp  4foo.c  foo.c  foo.cpp  Lindent
$ gcc -E -P 4foo.c -o 4foo.cpp
$ ./Lindent 4foo.cpp -o _4foo.cpp
$ cat _4foo.cpp
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);
        __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);
}
$

3.6 展开 SYSCALL_TRACE_ENTER_EVENT 和 SYSCALL_TRACE_EXIT_EVENT

### 感觉上面一节中Lindent格式化的依旧不够好看, 这里手动在改下_4foo.cpp, 插入一些换行和空行, 及对其
$ vim _4foo.cpp
$ cat _4foo.cpp > 5foo.c
## 添加SYSCALL_TRACE_ENTER_EVENT 和 SYSCALL_TRACE_EXIT_EVENT的宏定义
$ vim 5foo.c
$ gcc -E -P 5foo.c -o 5foo.cpp
$ ./Lindent 5foo.cpp -o _5foo.cpp
$ cat _5foo.cpp


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)
};



static struct syscall_metadata __syscall_meta__open;

static struct ftrace_event_call __used event_enter__open = {
        .class = &event_class_syscall_enter,
        {.name = "sys_enter" "_open",},
        .event.funcs = &enter_syscall_print_funcs,
        .data = (void *)&__syscall_meta__open,
        .flags = TRACE_EVENT_FL_CAP_ANY,
};

static struct ftrace_event_call __used
    __attribute__ ((section("_ftrace_events")))
    * __event_enter__open = &event_enter__open;;



static struct syscall_metadata __syscall_meta__open;

static struct ftrace_event_call __used event_exit__open = {
        .class = &event_class_syscall_exit,
        {.name = "sys_exit" "_open",},
        .event.funcs = &exit_syscall_print_funcs,
        .data = (void *)&__syscall_meta__open,
        .flags = TRACE_EVENT_FL_CAP_ANY,
};

static struct ftrace_event_call __used
    __attribute__ ((section("_ftrace_events")))
    * __event_exit__open = &event_exit__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);
        __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);
}

$

3.7 展开剩余的 __MAP, __PROTECT, __SC_XXX等

这里主要对一些类型定义, 参数定义的展开进行详细的描述

3.7.1 对_MAP 及 __SC_STR_TDECL 的一步步展开过程
__MAP(3, __SC_STR_TDECL, const char __user *, filename, int, flags, umode_t, mode)

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)

__MAP3(__SC_STR_TDECL, const char __user *, filename, int, flags, umode_t, mode)

==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)

__SC_STR_TDECL(const char __user *,filename), __MAP2(__SC_STR_TDECL,int, flags, umode_t, mode)

==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)

__SC_STR_TDECL(const char __user *,filename), __SC_STR_TDECL(int,flags), __MAP1(__SC_STR_TDECL,umode_t, mode)

==> #define __MAP1(m,t,a) m(t,a)

__SC_STR_TDECL(const char __user *,filename), __SC_STR_TDECL(int,flags), __SC_STR_TDECL(umode_t,mode)

==> #define __SC_STR_TDECL(t, a)    #t

"const char __user *", "int", "umode_t"
3.7.2 对 __SC_STR_ADECL 的展开
__MAP(3, __SC_STR_ADECL, const char __user *, filename, int, flags, umode_t, mode)

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)
==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
==> #define __MAP1(m,t,a) m(t,a)

__SC_STR_ADECL(const char __user *,filename), __SC_STR_ADECL(int,flags), __SC_STR_ADECL(umode_t,mode)

==> #define __SC_STR_ADECL(t, a)    #a

"filename", "flags", "mode"
3.7.3 对 __SC_DECL 的展开
__MAP(3, __SC_DECL, const char __user *, filename, int, flags, umode_t, mode)

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)
==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
==> #define __MAP1(m,t,a) m(t,a)

__SC_DECL(const char __user *,filename), __SC_DECL(int,flags), __SC_DECL(umode_t,mode)

==> #define __SC_DECL(t, a) t a

const char __user * filename, int flags, umode_t mode
3.7.4 对 __SC_LONG 的展开
__MAP(3, __SC_LONG, const char __user *, filename, int, flags, umode_t, mode);

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)
==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
==> #define __MAP1(m,t,a) m(t,a)

__SC_LONG(const char __user *,filename), __SC_LONG(int,flags), __SC_LONG(umode_t,mode);

==> #define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a

__typeof(__builtin_choose_expr(__TYPE_IS_LL(const char __user *), 0LL, 0L)) filename, 
__typeof(__builtin_choose_expr(__TYPE_IS_LL(int), 0LL, 0L)) flags, 
__typeof(__builtin_choose_expr(__TYPE_IS_LL(umode_t), 0LL, 0L)) mode;
3.7.5 对 __SC_CAST 的展开
__MAP(3, __SC_CAST, const char __user *, filename, int, flags, umode_t, mode);

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)
==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
==> #define __MAP1(m,t,a) m(t,a)

__SC_CAST(const char __user *,filename), __SC_CAST(int,flags), __SC_CAST(umode_t,mode);

==> #define __SC_CAST(t, a) (t) a

(const char __user *) filename, (int) flags, (umode_t) mode;
3.7.6 对 __SC_TEST 及 __TYPE_IS_LL 的展开
__MAP(3, __SC_TEST, const char __user *, filename, int, flags, umode_t, mode);

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)
==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
==> #define __MAP1(m,t,a) m(t,a)

__SC_TEST(const char __user *,filename), __SC_TEST(int,flags), __SC_TEST(umode_t,mode);

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

(void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(const char __user *) && sizeof(const char __user *) > sizeof(long)), 
(void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(int) && sizeof(int) > sizeof(long)), (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(umode_t) && sizeof(umode_t) > sizeof(long));

==> #define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL))

(void)BUILD_BUG_ON_ZERO(!(__same_type((const char __user *)0, 0LL) || __same_type((const char __user *)0, 0ULL)) && sizeof(const char __user *) > sizeof(long)), 
(void)BUILD_BUG_ON_ZERO(!(__same_type((int)0, 0LL) || __same_type((int)0, 0ULL)) && sizeof(int) > sizeof(long)), 
(void)BUILD_BUG_ON_ZERO(!(__same_type((umode_t)0, 0LL) || __same_type((umode_t)0, 0ULL)) && sizeof(umode_t) > sizeof(long));
3.7.7 对 __SC_ARGS 的展开
__MAP(3, __SC_ARGS, const char __user *, filename, int, flags, umode_t, mode);

==> #define __MAP(n,...) __MAP##n(__VA_ARGS__)
==> #define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
==> #define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
==> #define __MAP1(m,t,a) m(t,a)

__SC_ARGS(const char __user *,filename), __SC_ARGS(int,flags), __SC_ARGS(umode_t,mode);

==> #define __SC_ARGS(t, a) a

filename, flags, mode;
3.7.8 综上, 把那些小宏都展开后
$ cat _5foo.cpp > 6foo.c
## 添加剩余那些宏的定义, 也就是将上述各个小宏的定义都放入文件6foo.c中
$ vim 6foo.c
$ gcc -E -P 6foo.c -o 6foo.cpp
$ ./Lindent 6foo.cpp -o _6foo.cpp
$ cat _6foo.cpp

static const char *types__open[] = {
        "const char __user *",
        "int",
        "umode_t"
};

static const char *args__open[] = {
        "filename",
        "flags",
        "mode"
};

static struct syscall_metadata __syscall_meta__open;
static struct ftrace_event_call __used event_enter__open = {
        .class = &event_class_syscall_enter,
        {.name = "sys_enter" "_open",},
        .event.funcs = &enter_syscall_print_funcs,
        .data = (void *)&__syscall_meta__open,
        .flags = TRACE_EVENT_FL_CAP_ANY,
};

static struct ftrace_event_call __used
    __attribute__ ((section("_ftrace_events")))
    * __event_enter__open = &event_enter__open;;


static struct syscall_metadata __syscall_meta__open;
static struct ftrace_event_call __used event_exit__open = {
        .class = &event_class_syscall_exit,
        {.name = "sys_exit" "_open",},
        .event.funcs = &exit_syscall_print_funcs,
        .data = (void *)&__syscall_meta__open,
        .flags = TRACE_EVENT_FL_CAP_ANY,
};

static struct ftrace_event_call __used
    __attribute__ ((section("_ftrace_events")))
    * __event_exit__open = &event_exit__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(const char __user * filename, int flags, umode_t mode)
__attribute__ ((alias(__stringify(SyS_open))));

static inline long
SYSC_open(const char __user * filename, int flags, umode_t mode);

asmlinkage long
SyS_open(
        __typeof (
                __builtin_choose_expr (
                        (
                                __same_type((const char __user *)0, 0LL) ||
                                 __same_type((const char __user *)0, 0ULL)
                        ), 0LL, 0L
                )
        ) filename,
        __typeof (
                __builtin_choose_expr (
                        (
                                 __same_type((int)0, 0LL) ||
                                 __same_type((int)0, 0ULL)
                        ), 0LL, 0L
                )
        ) flags,
        __typeof (
                __builtin_choose_expr (
                        (
                                __same_type((umode_t) 0, 0LL) ||
                                __same_type((umode_t) 0, 0ULL)
                        ), 0LL, 0L
                )
        ) mode
);

asmlinkage long
SyS_open(
        __typeof (
                __builtin_choose_expr (
                        (
                                __same_type((const char __user *)0, 0LL) ||
                                 __same_type((const char __user *)0, 0ULL)
                        ), 0LL, 0L
                )
        ) filename,
        __typeof (
                __builtin_choose_expr (
                        (
                                __same_type((int)0, 0LL) ||
                                 __same_type((int)0, 0ULL)), 0LL, 0L
                )
        ) flags,
        __typeof (
                __builtin_choose_expr (
                        (
                                __same_type((umode_t) 0, 0LL) ||
                                __same_type((umode_t) 0, 0ULL)
                        ), 0LL, 0L
                )
        ) mode
) {
        long ret = SYSC_open((const char __user *)filename,
                        (int)flags, (umode_t) mode);

        (void) BUILD_BUG_ON_ZERO(
                !(
                        __same_type((const char __user *)0, 0LL) ||
                        __same_type((const char __user *)0, 0ULL)
                ) && sizeof(const char __user *) > sizeof(long)
        ),

        (void) BUILD_BUG_ON_ZERO(
                !(
                        __same_type((int)0, 0LL) ||
                        __same_type((int)0, 0ULL)
                ) && sizeof(int) > sizeof(long)
        ),

        (void) BUILD_BUG_ON_ZERO(
                !(
                        __same_type((umode_t) 0, 0LL) ||
                        __same_type((umode_t) 0, 0ULL)
                ) && sizeof(umode_t) > sizeof(long)
        );

        asmlinkage_protect(3, ret, filename, flags, mode);

        return ret;
}

static inline long
SYSC_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);
}
$

3.8 最终的定义

根据上述步骤层层展开, 可以看到
open系统调用:
SYSCALL_DEFINE3(open, …)
展开为
SYSC_open(), 而且SYSC_open()是被SyS_open()调用的, 由下面这句话知道, SyS_open是sys_open的别名.

asmlinkage long
sys_open(const char __user * filename, int flags, umode_t mode)
__attribute__ ((alias(__stringify(SyS_open))));

为了便于看出open的主旨, 可以将上述详细的展开, 除去枝节, 只留下函数主干逻辑, 就是如下的样子:


asmlinkage long
sys_open(const char __user * filename, int flags, umode_t mode)
__attribute__ ((alias(__stringify(SyS_open))));

static inline long
SYSC_open(const char __user * filename, int flags, umode_t mode);

asmlinkage long
SyS_open((const char __user *) filename, int flags, (umode_t)  mode);

asmlinkage long
SyS_open((const char __user *) filename, int flags, (umode_t)  mode) 
{
        long ret = SYSC_open((const char __user *)filename,
                        (int)flags, (umode_t) mode);
        return ret;
}

static inline long
SYSC_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);
}

所以, open()系统调用其实是这么干的:
sys_open() == SyS_open() —> SYSC_open() —> do_sys_open()

这具有一般性, 也就是说:
任何一个系统调用 xxx() 都是 (基于当前Linux Kernel 4.0 代码的实现)
sys_xxx() === SyS_xxx() —> SYSC_xxx() —> …(各系统调用自己的特定实现)


/* for system call xxx() 
 *
 * SYSCALL_DEFINEn(xxx, type1, arg1, type2, arg2, ..., typen, argn)
 * {
 *        ...
 *		  /* specific implementation */
 *        ...
 * }
 */


asmlinkage long
sys_xxx(type1 arg1, type2 arg2, ..., typen argn)
__attribute__ ((alias(__stringify(SyS_xxx))));

static inline long
SYSC_xxx(type1 arg1, type2 arg2, ..., typen argn);

asmlinkage long
SyS_xxx((type1) arg1, (type2) arg2, ..., (typen) argn);

asmlinkage long
SyS_xxx((type1) arg1, (type2) arg2, ..., (typen) argn) 
{
        long ret = SYSC_xxx((type1) arg1, (type2) arg2, ..., (typen) argn);
        return ret;
}

static inline long
SYSC_xxx(type1 arg1, type2 arg2, ..., typen argn)
{
		...
		/* specific implementation */
		...
}

4 参考

https://blog.csdn.net/hxmhyp/article/details/22699669
用gcc的-E选项来查看宏展开

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值