为了新增一个 vdso 系统调用,需要同时修改内核和 glibc。glib 支持多种体系结构和操作系统,在 gblic 中新增一个 vdso 系统调用,需要在对应体系结构目录下新增一个包含该系统调用的 .c 文件,比如 ./sysdeps/unix/sysv/linux/x86/gettimeofday.c 文件,它定义了 gettimeofday() 这个系统调用的 vdso 版本的调用流程,内容如下所示:
#include <sys/time.h>
#ifdef SHARED
# include <dl-vdso.h>
# include <errno.h>
static int
__gettimeofday_syscall (struct timeval *tv, struct timezone *tz)
{
return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
}
# ifndef __gettimeofday_type
/* The i386 gettimeofday.c includes this file with a defined
__gettimeofday_type macro. For x86_64 we have to define it to __gettimeofday
as the internal symbol is the ifunc'ed one. */
# define __gettimeofday_type __gettimeofday
# endif
# undef INIT_ARCH
# define INIT_ARCH() PREPARE_VERSION_KNOWN (linux26, LINUX_2_6)
/* If the vDSO is not available we fall back to syscall. */
libc_ifunc_hidden (__gettimeofday_type, __gettimeofday,
(_dl_vdso_vsym ("__vdso_gettimeofday", &linux26)
?: &__gettimeofday_syscall))
libc_hidden_def (__gettimeofday)
#else
# include <sysdep.h>
# include <errno.h>
int
__gettimeofday (struct timeval *tv, struct timezone *tz)
{
return INLINE_SYSCALL (gettimeofday, 2, tv, tz);
}
libc_hidden_def (__gettimeofday)
#endif
weak_alias (__gettimeofday, gettimeofday)
libc_hidden_weak (gettimeofday)
上述代码通过一系列宏实现了系统调用 gettimeofday() 的两种调用方式,它们分别是:
1)通过 _dl_vdso_vsym() 函数查找 __vdso_gettimeofday() 函数地址,走 vdso 版的系统调用流程;
2)通过 INLINE_SYSCALL (gettimeofday, 2, tv, tz) 走普通的系统调用流程。
总结起来就是,当 vdso 可用时,则走 vdso 流程,当 vdso 不可用时,则走普通的系统调用流程。