delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

19 Dec 2005

关于system call

FreeBSD 开发手册 中,有一部分内容介绍了关于系统调用。里面有这样一段话:

Linux is a UNIX like system. However, its kernel uses the same system-call convention of passing parameters in registers MS-DOS does. As with the UNIX convention, the function number is placed in EAX. The parameters, however, are not passed on the stack but in EBX, ECX, EDX, ESI, EDI, EBP:

open:
  mov eax, 5
  mov ebx, path
  mov ecx, flags
  mov edx, mode
  int 80h

This convention has a great disadvantage over the UNIX way, at least as far as assembly language programming is concerned: Every time you make a kernel call you must push the registers, then pop them later. This makes your code bulkier and slower. Nevertheless, FreeBSD gives you a choice.

可能有人会问了,为什么说 UNIX way (将参数压栈) 更好呢?

答案是显然的, UNIX way 不仅更为清晰,而且性能更好。

为什么这样说呢?

使用寄存器来传递参数有很多问题。

·在调用前必须保存所有可能受到影响的寄存器。
·调用返回之后,需要将有用的数据从寄存器中放回内存。
·然后恢复寄存器内容。

这样,我们可以看到,按照MS-DOS的调用约定,我们会需要压栈、设置参数、陷kernel、保存返回值、出栈。这样,程序会变得庞大而臃肿。当然,这种做法也并非一无是处,就是如果需要hack的话,你会在前后有更多的空间(CD 80 vs 一大堆PUSH, MOV, POP)。

目前为止,FreeBSD还没有实现使用SYSENTER/SYSEXIT的系统调用方法。在IASDM的第二卷的Instruction Set Reference一节对此进行了介绍。这种做法,与先前的int 0x80相比,int 0x80需要CPU从全局描述符表中取出0x80对应的8个字节指针,这需要进行一系列权限检查,等等。很明显,如果CPU明确地知道系统调用对应的一系列入口的位置,就能够显著地降低这部分的开销了。