Linux系统调用01

Linux系统调用的整体流程为:
1、应用程序【用户态】通过syscall或glibc进行内核功能调用,这一部分在glibc源码中进行的
2、CPU收到syscall,Linux内核响应syscall调用【内核态】,这一部分在linux源码中进行的
3、返回结果到应用程序【用户态】
本节先处理第一部分:

一、glibc部分
1、应用程序调用open函数

//glibc/intl/loadmsgcat.c
# define open(name, flags)  __open_nocancel (name, flags)

2、展开后实际上调用了

__open_nocancel(name, flags)

3、而__open_nocancel 最终调用了INLINE_SYSCALL_CALL

//glibc/sysdeps/unix/sysv/linux/open_nocancel.c
__open_nocancel(name, flags)
->return INLINE_SYSCALL_CALL (openat, AT_FDCWD, file, oflag, mode);

4、宏展开【理解就好,不保证顺序】

4.1、初始为

INLINE_SYSCALL_CALL (openat, AT_FDCWD, file, oflag, mode);

4.2、第1次展开INLINE_SYSCALL_CALL

#define INLINE_SYSCALL_CALL(...) \
  __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__)

//展开得到:
__INLINE_SYSCALL_DISP(__INLINE_SYSCALL, __VA_ARGS__【openat, AT_FDCWD, file, oflag, mode】)

4.3、第2次展开__INLINE_SYSCALL_DISP

#define __INLINE_SYSCALL_DISP(b,...) \
  __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)

//展开得到:
__SYSCALL_CONCAT(b【__INLINE_SYSCALL】,__INLINE_SYSCALL_NARGS(__VA_ARGS__【openat, AT_FDCWD, file, oflag, mode】))(__VA_ARGS__【openat, AT_FDCWD, file, oflag, mode】)

4.4、第3次展开__INLINE_SYSCALL_NARGS

__INLINE_SYSCALL_NARGS(__VA_ARGS__【openat, AT_FDCWD, file, oflag, mode】)

#define __INLINE_SYSCALL_NARGS(...) \
  __INLINE_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,)

//展开得到:
__INLINE_SYSCALL_NARGS_X(openat, AT_FDCWD, file, oflag, mode,7,6,5,4,3,2,1,0,)

//然后展开__INLINE_SYSCALL_NARGS_X
#define __INLINE_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n

//展开得到参数个数:
4

//从而4.4的结果为
__SYSCALL_CONCAT(__INLINE_SYSCALL,4)(__VA_ARGS__【openat, AT_FDCWD, file, oflag, mode】)

4.5、然后展开__SYSCALL_CONCAT,其实就是字符拼接

__SYSCALL_CONCAT(__INLINE_SYSCALL,4)

#define __SYSCALL_CONCAT_X(a,b)     a##b
#define __SYSCALL_CONCAT(a,b)       __SYSCALL_CONCAT_X (a, b)

//展开得到:
__INLINE_SYSCALL4

//从而4.5的结果为
__INLINE_SYSCALL4(openat, AT_FDCWD, file, oflag, mode)

4.6、然后展开INTERNAL_SYSCALL4

#define __INLINE_SYSCALL4(name, a1, a2, a3, a4) \
  INLINE_SYSCALL (name, 4, a1, a2, a3, a4)

//展开得到:
INLINE_SYSCALL(openat, 4, AT_FDCWD, file, oflag, mode)

4.7、展开INLINE_SYSCALL

//glibc/sysdeps/unix/sysv/linux/sysdep.h
#define INLINE_SYSCALL(name, nr, args...)       \
  ({                  \
    long int sc_ret = INTERNAL_SYSCALL (name, nr, args);    \
    __glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (sc_ret))    \
    ? SYSCALL_ERROR_LABEL (INTERNAL_SYSCALL_ERRNO (sc_ret))   \
    : sc_ret;               \
  })

//展开得到
INTERNAL_SYSCALL (openat, 4, args【AT_FDCWD, file, oflag, mode】);  

4.8、展开INTERNAL_SYSCALL

#define INTERNAL_SYSCALL(name, nr, args...)       \
  internal_syscall##nr (SYS_ify (name), args)

//展开得到
internal_syscall4(SYS_ify(openat), args【AT_FDCWD, file, oflag, mode】)

//展开 SYS_ify(openat)
#define SYS_ify(syscall_name) __NR_##syscall_name
//得到
__NR_openat

//从而得到
internal_syscall4(__NR_openat, args【AT_FDCWD, file, oflag, mode】)

4.9、最后internal_syscall4中,汇编调用了syscall

glibc\sysdeps\unix\sysv\linux\x86_64\64\arch-syscall.h
#define __NR_openat 257

最终,syscall时,先传入调用号257,然后是四个真正的参数。

Leave a Reply

Your email address will not be published.

*