Linux系统调用与实例分析
计算机961班 林霁 9615018
一. 系统调用的基本概念
通常,在OS的核心中都设置了一组用于实现各种系统功能的子程序(过程),并将它们提供给用户调用。每当用户在程序中需要OS提供某种服务时,便可利用一条系统调用命令,去调用系统过程。它一般运行在核心态;通过软中断进入;返回时通常需要重新调度(因此不一定直接返回到调用过程)。
系统调用是沟通用户(应用程序)和操作系统内核的桥梁。
二. Linux的系统调用
Linux系统调用的流程非常简单,它由0x80号软中断进入系统调用入口,通过使用系统调用表保存系统调用服务函数的入口地址来实现。
2.1 Linux系统调用的数据结构
在文件“arch/i386/entry.S”中定义了系统调用表(sys_call_table),该表保存了Linux的所有基于Intel x86系列体系结构的计算机的166个系统调用入口地址(其中3个保留,Linux开辟的系统调用表可容纳256项),其中每项都被说明成 long型。下面是其中几项:
.data
ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_setup) .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork)
1
/* 0 */
…… ……
.long SYMBOL_NAME(sys_nanosleep) /* 162 */ .long SYMBOL_NAME(sys_mremap) .long 0,0
.long SYMBOL_NAME(sys_vm86) .space (NR_syscalls-166)*4
NR_syscalls是在“include/linux/sys.h”文件中定义的宏,其值为256,表示x86微机上最多可容纳的系统调用个数。
在文件“include/asm-i386/ptrace.h”中定义了一种寄存器帧结构 struct pt_regs { };
2
long ebx; long ecx; long edx; long esi; long edi; long ebp; long eax;
unsigned short ds, __dsu; unsigned short es, __esu; unsigned short fs, __fsu; unsigned short gs, __gsu; long orig_eax; long eip;
unsigned short cs, __csu; long eflags; long esp;
unsigned short ss, __ssu;
该帧结构定义了各寄存器在系统调用时保存现场的堆栈结构。
2.2 设置0x80 软中断
Linux的系统调用由0x80号软中断进入,中断向量表的初始化在系统启动时进行,各种trap入口start_kernel()函数(init/main.c)中通过调用trap_init()(
arch/i386/kernel/traps.c
)
被
设
置
,
其
中
set_system_gate(0x80,&system_call)设置了0x80号软中断。
“set_system_gate()”是一个宏,它在“include/asm-i386/system.h”中被定义。调用该宏,将使addr地址值置入gate_addr中的地址值所指向的内存单元中,以上过程,使中断向量描述表中的第128项(即16进制第80项)保存了0x80号中断的中断服务程序,即system_call的入口地址。
2.3系统调用入口
在头文件“include/asm-i386/unistd.h”中,定义了一系列的与系统调用有关的宏,包括系统调用序号,如:
#define __NR_setup #define __NR_exit #define __NR_fork #define __NR_read
还定义了设置系统调用入口的宏,_syscallX(),其中X表示系统调用的参数个数,Linux定义的各种系统调用的参数个数不超过5个,因此,在5)。
下面以_syscall2()为例:
#define _syscall2(type,name,type1,arg1,type2,arg2) \\ type name(type1 arg1,type2 arg2) \\ { \\
3
0 1 2 3
该文件中,共定义了6个宏
(_syscall0(type,name),……,_syscall5(type,name,type1,arg1,……,type5,arg