1 概述
vsyscall和vDSO是用于加速某些系统调用的两种机制。
传统的int 0x80有点慢, Intel和AMD分别实现了sysenter/sysexit和syscall/ sysret, 即所谓的快速系统调用指令, 使用它们更快, 但是也带来了兼容性的问题. 于是Linux实现了vsyscall, 程序统一调用vsyscall, 具体的选择由内核来决定. 而vsyscall的实现就在VDSO中。
【vsyscall】
用来执行特定的系统调用,减少系统调用的开销。某些系统调用并不会向内核提交参数,而仅仅只是从内核里请求读取某个数据,例如gettimeofday(),内核在处理这部分系统调用时可以把系统当前时间写在一个固定的位置(由内核在每个时间中断里去完成这个更新动作),mmap映射到用户空间。这样会更快速,避免了传统系统调用模式INT 0x80/SYSCALL造成的内核空间和用户空间的上下文切换。
【vsyscall的局限】
分配的内存较小;
只允许4个系统调用;
Vsyscall页面在每个进程中是静态分配了相同的地址;
【vDSO】
提供和vsyscall相同的功能,同时解决了其局限。
vDSO是动态分配的,地址是随机的;
可以提供超过4个系统调用;
vDSO是glibc库提供的功能;
2 X64
测试环境Ubuntu 16.04
2.1 查看vsyscall/VDSO内存映射
millionsky@ubuntu-16:~/tmp/VDSO$ cat /proc/`pgrep cat | head -1`/maps | egrep 'vdso|vsyscall'
7ffdb57da000-7ffdb57dc000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
2.2 导出VDSO/vsyscall
2.2.1 Gdb导出vdso/vsyscall
millionsky@ubuntu-16:~/tmp/VDSO$ gdb -q /bin/ls Reading symbols from /bin/ls...(no debugging symbols found)...done. (gdb) tb __open Function "__open" not defined. Make breakpoint pending on future shared library load? (y or [n]) y Temporary breakpoint 1 (__open) pending. (gdb) r Starting program: /bin/ls
Temporary breakpoint 1, open64 () at ../sysdeps/unix/syscall-template.S:84 84 ../sysdeps/unix/syscall-template.S: 没有那个文件或目录. (gdb) info program Using the running image of child process 12012. Program stopped at 0x7ffff7df2320. It stopped at a breakpoint that has since been deleted. Type "info stack" or "info registers" for more information. (gdb) shell cat /proc/12012/maps | grep vdso 7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0 [vdso] (gdb) dump memory /tmp/linux-vdso.so.1 0x7ffff7ffa000 0x7ffff7ffc000 (gdb) q |
同样的方法可以导出vsyscall
2.2.2 python导出vdso
这里是Python调用的C库函数