传统的系统调用是怎样的?    —— int 0x80的时代

....             ;通过寄存器传参
mov $n ,eax ;将系统调用号放到eax中
int 0x80

sysenter/sysexit的出场

在一个Kernel.org的邮件列表中,有一封邮件讨论了“"Intel P6 vs P7 system call performance”,最后得出的结论是采用传统的int 0x80的系统调用浪费了很多时间(具体原因可以看参考资料1),而sysenter/sysexit可以弥补这个缺点,所以决定在linux内核中用后都替换前者(最终在2.6版本的内核中才加入了此功能,即采用sysenter/sysexit)。

在替换之前首先需要知道满足如下条件的ntel机器才会有sysenter/sysexit指令对:Family >= 6,Model >= 3,Stepping >= 3

如何用替换sysenter/sysexit替换以前的int 0x80呢?linux kenerl 需要考虑到这点:有的机器并不支持sysenter/sysexit  , 于是它跟glibc说好了,“你以后调用系统调用的时候就从我给你的这个地址调用,这个地址指向的内容要么是int 0x80调用方式,要么是sysenter/sysexit调用方式,我会根据机器来选择其中一个”(kernel与glibc的配合是如此的默契),这个地址便是vsyscall的首地址。

可以将vdso看成一个shared objdect file(这个文件实际上不存在),内核将其映射到某个地址空间,被所有程序所共享。(我觉得这里用到了一个技术:多个虚拟页面映射到同一个物理页面。即内核把vdso映射到某个物理页面上,然后所有程序都会有一个页表项指向它,以此来共享,这样每个程序的vdso地址就可以不相同了)

hex108@ubuntu:~/program$ uname -a
Linux ubuntu 2.6.35-22-generic #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010 i686 GNU/Linux
hex108@ubuntu:~/program$ sudo sysctl -w kernel.randomize_va_space=0 //这个是必须的,否则vdso的地址是随机的(vsyscall的地址也会相应
                                                                        // 地发生变化 ),在下面dd的时候就会出现错误
                                                                        //dd: reading `/proc/self/mem': Input/output error
kernel.randomize_va_space = 0
hex108@ubuntu:~/program$ cat /proc/self/maps
00110000-0012c000 r-xp 00000000 08:01 260639 /lib/ld-2.12.1.so
0012c000-0012d000 r--p 0001b000 08:01 260639 /lib/ld-2.12.1.so
0012d000-0012e000 rw-p 0001c000 08:01 260639 /lib/ld-2.12.1.so
0012e000-0012f000 r-xp 00000000 00:00 0 [vdso]
0012f000-00286000 r-xp 00000000 08:01 260663 /lib/libc-2.12.1.so
00286000-00287000 ---p 00157000 08:01 260663 /lib/libc-2.12.1.so
00287000-00289000 r--p 00157000 08:01 260663 /lib/libc-2.12.1.so
00289000-0028a000 rw-p 00159000 08:01 260663 /lib/libc-2.12.1.so
0028a000-0028d000 rw-p 00000000 00:00 0
08048000-08051000 r-xp 00000000 08:01 130326 /bin/cat
08051000-08052000 r--p 00008000 08:01 130326 /bin/cat
08052000-08053000 rw-p 00009000 08:01 130326 /bin/cat
08053000-08074000 rw-p 00000000 00:00 0 [heap]
b7df0000-b7ff0000 r--p 00000000 08:01 660864 /usr/lib/locale/locale-archive
b7ff0000-b7ff1000 rw-p 00000000 00:00 0
b7ffd000-b7ffe000 r--p 002a1000 08:01 660864 /usr/lib/locale/locale-archive
b7ffe000-b8000000 rw-p 00000000 00:00 0
bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
hex108@ubuntu:~/program$ dd if=/proc/self/mem of=gate.so bs=4096 skip=$[0x12e] count=1
dd: `/proc/self/mem': cannot skip to specified offset
1+0 records in
1+0 records out
4096 bytes (4.1 kB) copied, 0.00176447 s, 2.3 MB/s
hex108@ubuntu:~/program$ file gate.so
gate.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, stripped
hex108@ubuntu:~/program$ objdump -d gate.so gate.so: file format elf32-i386 Disassembly of section .text: ffffe400 <__kernel_sigreturn>:
ffffe400: 58 pop %eax
ffffe401: b8 77 00 00 00 mov $0x77,%eax
ffffe406: cd 80 int $0x80
ffffe408: 90 nop
ffffe409: 8d 76 00 lea 0x0(%esi),%esi ffffe40c <__kernel_rt_sigreturn>:
ffffe40c: b8 ad 00 00 00 mov $0xad,%eax
ffffe411: cd 80 int $0x80
ffffe413: 90 nop ffffe414 <__kernel_vsyscall>:
ffffe414: cd 80 int $0x80
ffffe416: c3 ret
 

syscall 才是最后的赢家?

x86 64位从AMD引进了syscall指令(我在x86 64的机器上,看到的结果是syscall取代了sysenter/sysexit(所有的系统调用用的都是syscall)),但是vdso,vsyscall的机制依旧未变,只是kernel决定只在遇到以下几个系统调用gettimeofday,time和getcpu(通过内核里vsyscall.h中enum vsyscall_num的声明看出来,或者在glibc源代码中搜索“VSYSCALL_ADDR_”(

#define VSYSCALL_ADDR_vgettimeofday    0xffffffffff600000

#define VSYSCALL_ADDR_vtime            0xffffffffff600400

#define VSYSCALL_ADDR_vgetcpu          0xffffffffff600800

))时才采用vdso机制(间接调用syscall,具体可以参看资料2),其他系统调用直接用指令syscall,原因是:


"快速系统调用指令"比起中断指令来说,其消耗时间必然会少一些,但是随着 CPU 设计的发展,将来应该不会再出现类似 Intel Pentium4 这样悬殊的差距。而"快速系统调用指令"比起中断方式的系统调用方式,还存在一定局限,例如无法在一个系统调用处理过程中再通过"快速系统调用指令"调用别的系统调用。因此,并不一定每个系统调用都需要通过"快速系统调用指令"来实现。比如,对于复杂的系统调用例如 fork,两种系统调用方式的时间差和系统调用本身运行消耗的时间来比,可以忽略不计,此处采取"快速系统调用指令"方式没有什么必要。而真正应该使用"快速系统调用指令"方式的,是那些本身运行时间很短,对时间精确性要求高的系统调用,例如 getuid、gettimeofday 等等。因此,采取灵活的手段,针对不同的系统调用采取不同的方式,才能得到最优化的性能和实现最完美的功能。      ----引自参考资料1

linux下的vdso与vsyscall的更多相关文章

  1. Linux下的段错误(Segmentation fault)

    Linux开发中常见段错误问题原因分析 1 使用非法的内存地址(指针),包括使用未经初始化及已经释放的指针.不存在的地址.受系统保护的地址,只读的地址等,这一类也是最常见和最好解决的段错误问题,使用G ...

  2. NodeJs在Linux下使用的各种问题

    环境:ubuntu16.04 ubuntu中安装NodeJs 通过apt-get命令安装后发现只能使用nodejs,而没有node命令 如果想避免这种情况请看下面连接的这种安装方式: 拓展见:Linu ...

  3. Linux下服务器端开发流程及相关工具介绍(C++)

    去年刚毕业来公司后,做为新人,发现很多东西都没有文档,各种工具和地址都是口口相传的,而且很多时候都是不知道有哪些工具可以使用,所以当时就想把自己接触到的这些东西记录下来,为后来者提供参考,相当于一个路 ...

  4. Linux下Nodejs安装(完整详细)

    之前安装过windows下以及Mac下的node,感觉还是很方便的,不成想今天安装linux下的坑了老半天,特此记录. 首先去官网下载代码,这里一定要注意安装分两种,一种是Source Code源码, ...

  5. (转载)linux下各个文件夹的作用

    linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配置文件和脚本 /home 用户主目录的基 ...

  6. 萌新笔记——linux下查看内存的使用情况

    windows上有各种软件可以进行"一键加速"之类的操作,释放掉一些内存(虽然我暂时不知道是怎么办到的,有待后续学习).而任务管理器也可以很方便地查看各进程使用的内存情况,如下图: ...

  7. [每日Linux]Linux下xsell和xftp的使用

    实验缘由: 1.xsell在Linux下的作用就是远程登录的一个界面,也就是实现访问在Windows下访问Linux服务器的功能.之前在数据挖掘实验中因为自己电脑的内存不够,曾经使用过实验室的服务器跑 ...

  8. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  9. 我将系统从Windows迁移至Linux下的点点滴滴

    一.写在最前 由于本人的技术水平有限,难免会出现错误.本文对任何一个人有帮助都是我莫大的荣幸,任何一个大神对我的点拨,我都会感激不尽. 二.技术选型 在2013年8月低的时候,公司中了XXX市场监督局 ...

随机推荐

  1. Linux oracle数据库创建表空间、用户并赋予权限

    管理员用户登录oracle数据库 1.创建临时表空间 select name from v$tempfile;查出当前数据库临时表空间,主要是使用里面的存放路径: 得到其中一条记录/opt/oracl ...

  2. SpringBoot(五)-- 整合Spring的拦截器

    一.步骤 1.创建我们自己的拦截器类并实现 HandlerInterceptor 接口. 2.创建一个Java类继承WebMvcConfigurerAdapter,并重写 addInterceptor ...

  3. 浅谈千万级PV/IP规模高性能高并发网站架构(转自老男孩)

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://oldboy.blog.51cto.com/2561410/736710 如果把来 ...

  4. MyBatis中Like语句使用总结

    原生写法 eg: select * from user where username like '%${value}%' 注意:     ${value}里面必须要写value,不然会报错 oracl ...

  5. MegaCli 使用

    安装: wget ftp://rpmfind.net/linux/Mandriva/devel/cooker/x86_64/media/non-free/release/megacli-8.02.21 ...

  6. 嵌入式系统C编程之堆栈回溯(二)

    前言 本文作为<嵌入式系统C编程之堆栈回溯>的补充版.文中涉及的代码运行环境如下: 一  异常信号 信号就是软件中断,用于向正在运行的程序(进程)发送有关异步事件发生的信息.Linux应用 ...

  7. WP8.1学习系列(第十七章)——Windows Phone重要图形、视觉指示器和通知

    美感在手机应用中是不可或缺的,它是直观操作的代名词.在 Windows Phone 中,你的磁贴.初始屏幕.图标.控件和导航的视觉元素会引起用户对应用程序内的相关任务.优先事项或操作的注意,并采用新颖 ...

  8. 使用IBM SVC构建vSphere存储间集群

    使用IBM SVC构建vSphere存储间集群 本文目的 本文描述利用IBM SVC来构建Vsphere 存储间集群 解决方案 什么是vMSC? vShpere存储间集群是一个针对VmwarevSpe ...

  9. Web服务器配置Gzip压缩提升网站性能

    前言: HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术.大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度.这一般是指WWW服务器中安装的一个功能,当有人来访问这个服 ...

  10. canvas练习 - 圆

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...