分类: LINUX
2010-06-03 19:27:50
系统调用是操作系统为用户提供的,用来能够让用户使用系统提供的各种功能。
系统调用和一般函数调用的区别:
(1)前者和后者运行在不同状态。在操作系统中有内核态(管态)和用户态(算态)之分。确切的说是系统调用的功能运行在内核态,而一般的函数调用运行在用户态,系统调用提供一个在用户态调用内核态功能的接口。
(2)两者调用方式不同,一般的函数调用在保护现场后,会直接转到被调用的函数地址执行,执行完毕后返回原程序继续执行;而系统调用则不能直接调用,需在利用软中断,声明进入内核态后,才能根据系统调用号进行调用。
标准库,系统调用和中断的调用关系:
在c语言中,我们可以调用标准库中的write函数执行写操作,write的函数原型如下:
ssize write(int __fd, __const void *__buf, size_t __n ) __wur;
前面说到系统调用是操作系统为用户提供的接口,但不同的操作系统系统调用的实现和提供方式都有可能不同,Linux,Unix以及Windows上的系统调用并不完全相同,甚至大相径庭。
“解决计算机的问题可以通过增加层来实现”。
标准库是对系统调用的封装,/usr/include/unistd.h定义了POSIX标准的接口。这是向上分析。
对于更底一层来说,write最终调用的是sys_write即4号调用,系统调用号在/arch/x86/include/asm中定义,
通过#define _syscallN宏将汇编代码封装成c函数,
#define _syscallN(type, name, type1, arg1, type2, arg2, . . . ) \
type name(type1 arg1,type2 arg2) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
. . . . . .
__syscall_return(type,__res); \
}
__asm__告诉编译器嵌入一段汇编代码,volatile告诉编译器不要对下面一段代码进行优化。
函数write(1, “hello”, 5)作用是以stdout方式输出hello字符串,将函数展开后应该得到类似下面的汇编代码,
xor eax, eax ;clean up the registers,SAVE_ALL,
xor ebx, ebx
xor edx, edx
xor ecx, ecx
mov al, 4 ;syscall write
mov bl, 1 ;stdout is 1
pop ecx ;get the address of the string from the stack
mov dl, 5 ;length of the string
int 0x80
将系统调用号存入al,4号调用为sys_write调用,ecx存入要打印数据地址,dl存入数据长度,bl标记输出方式。
此时,数据已经准备好,int 0x80号中断为linux下系统调用的入口。当执行到int 0x80后,查找中断向量表(在/arch/x86/include/asm/irq_vectors.h中定义),调用int 0x80号中断服务,cpu由用户态转为内核态;根据eax(存有的系统调用号)查找具体的系统调用,执行完后返回原程序,继续执行。
上面这种基于int指令的系统调用在较新的一些处理器上性能不佳,在最近的linux版本(linux2.5+)中,又引入了一种新的系统调用机制,sysenter和sysexit,这两个指令时intel在奔腾2代处理器开始支持的一组专门针对系统调用的指令。详细内容参考Intel的Cpu指令手册,以及linux源代码。推荐文章http://www.ibm.com/developerworks/cn/linux/kernel/l-k26ncpu/index.html
Linux上的系统调用和Windows上的系统调用不同:
Linux, unlike windows, provides a direct way to interface with the kernel through the int 0x80 interface. A complete listing of the Linux syscall table can be found here. Windows on the other hand, does not have a direct kernel interface. The system must be interfaced by loading the address of the function that needs to be executed from a DLL (Dynamic Link Library). The key difference between the two is the fact that the address of the functions found in windows will vary from OS version to OS version while the int 0x80 syscall numbers will remain constant. Windows programmers did this so that they could make any change needed to the kernel without any hassle; Linux on the contrary has fixed numbering system for all kernel level functions, and if they were to change, there would be a million angry programmers (and a lot of broken code).(节自)
Windws为程序员提供api,但系统调用入口是可变的,我们可以使用特殊的工具查找系统调用的地址(只需知道它的名字即可),然后使用call 指令调用。
附:
Linux System Call Table:
Windows System Call Table: