天外有天,人外有人。
分类: LINUX
2013-09-04 22:36:44
系统调用通过软中断0x80来使系统切换到内核态执行第0x80号中断服务程序,中断则定义有entry.S中:
ENTRY(system_call)
cmpl $(nr_syscalls), %eax #eax寄存器中放的是系统调用号,判断是否为有效系统调用号
jae syscall_badsys
syscall_call:
call*sys_call_table(,%eax,4) #sys_call_table是syscall_tables.S中定义的#///系统调用表(数组)的起始地址,4为table中各项占用字节数
2.4相关文件:
Arch/kernel/entry.S 定义ENTRY(sys_call_table)
Include/Linux/Sys.h #define NR_syscalls 256规定了syscalls的最大个数
2.6相关文件:
为了更增可读性,2.6中将原位于entry.S中的ENTRY(sys_call_table)拿出来单独放在Arch/kernel/syscall_tables.S 中,不过也include到entry.S中了。2.6.15内核有294个.
Arch/kernel/entry.S中计算系统调用表的大小的方法:
#include "syscall_table.S" //定义系统调用表
syscall_table_size=(.-sys_call_table)
相同点: 实现机制上没有太大的区别。内核在执行系统调用时处于进程上下文,current指向系统调用的那个进程。
例:(内核中现成的)
1. arch/kernel/syscall_table.S 系统表中加入相应表项 .long sys_getpid /*20*/
2. include/asm/unistd.h 中加入系统调用号 #define __NR_getpid 20
3. 系统调用代码实现:
asmlinkage long sys_getpid(void)
{
return current->tgid;
}
4.一般系统调用由glibc提供支持,用户通过头文件和glibc库链接实现。也可以用_syscallN(…)宏来实现,其中N是0-6,代表参数个数,在使用调用前声明该宏(从宏的定义中可以看出其作用)。
#define _syscall0(type,name) \ //其实就是定义一个ox80号中断
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \ //参数,类似__NR_getpid这样的系统调用号
__syscall_return(type,__res); \ //置errno值
}
注意,系统调用不能随便更改,否则许多原有程序可能无法使用。