加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 教程 > 正文

Linux系统调用步骤

发布时间:2021-12-15 11:32:22 所属栏目:教程 来源:互联网
导读:一. 概述 Linux系统调用是应用程序与内核交互的一种方式。系统调用作为一种接口,通过系统调用,应用程序能够进入操作系统内核,从而使用内核提供的各种资源,比如操作硬件,开关中断,改变特权模式等等。首先,系统调用是一个软中断,既然是中断那么一般就

一. 概述
 
Linux系统调用是应用程序与内核交互的一种方式。系统调用作为一种接口,通过系统调用,应用程序能够进入操作系统内核,从而使用内核提供的各种资源,比如操作硬件,开关中断,改变特权模式等等。首先,系统调用是一个软中断,既然是中断那么一般就具有中断号和中断处理程序两个属性,Linux使用0x80号中断作为系统调用的入口,而中断处理程序的地址放在中断向量表里。
 
二. 过程
 
基于linux-2.6.38,以read()系统调用函数为例进行说明。
 
在用户空间,read()函数的声明位于#include<unistd.h>,原型为:ssize_t read(int fd, void *buf, size_t count)。下面是read()函数在用户空间的定义的伪代码:
 
ssize_t read(int fd, void *buf, size_t count)
 {
        long res;
        %eax = __NR_read
        %ebx = fd
        %ecx = (long)buf
        %edx= count
        int $0x80
        res = %eax
        return res;
 }
 
第4行,用eax寄存器保存read()的系统调用号,在/arch/x86/include/asm/unistd_32.h里定义(#define __NR_read  3);第5~7行,分别将三个参数放入三个寄存器(通过寄存器来传递参数);第8行,执行系统调用,进入内核;第9行,获取eax寄存器所保存的函数返回值。
 
执行第8行后已经进入了系统内核,由于这是一个中断,因此程序进入到中断向量表中记录0x80号的中断处理程序,中断向量表的初始化在/arch/x86/kernel/traps.c中定义:
 
void __init trap_init(void)
 {
 ...................
 
    #ifdef CONFIG_X86_32
        set_system_trap_gate(SYSCALL_VECTOR, &system_call);
        set_bit(SYSCALL_VECTOR, used_vectors);
    #endif
 ...................
 }
 
如第6行所示。SYSCALL_VECTOR是系统调用的中断号,在/arch/x86/include/asm/irq_vectors.h中定义:
 
#ifdef CONFIG_X86_32
# define SYSCALL_VECTOR            0x80
#endif
 
正好是0x80。而system_call是系统调用的中断处理函数指针,用户执行int $0x80后会执行到这个函数,它在/arch/x86/kernel/entry_32.S中定义:
 
ENTRY(system_call)
     RING0_INT_FRAME            # can't unwind into user space anyway
     pushl_cfi %eax            # save orig_eax
     SAVE_ALL
     GET_THREAD_INFO(%ebp)
                     # system call tracing in operation / emulation
     testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
     jnz syscall_trace_entry
     cmpl $(nr_syscalls), %eax
     jae syscall_badsys
 syscall_call:
     call *sys_call_table(,%eax,4)
     movl %eax,PT_EAX(%esp)        # store the return value
...........
 
第4行,SAVE_ALL是一个宏,也在这个文件里定义:
 
.macro SAVE_ALL
     cld
     PUSH_GS
     pushl_cfi %fs
     /*CFI_REL_OFFSET fs, 0;*/
     pushl_cfi %es
     /*CFI_REL_OFFSET es, 0;*/
     pushl_cfi %ds
     /*CFI_REL_OFFSET ds, 0;*/
     pushl_cfi %eax
     CFI_REL_OFFSET eax, 0
     pushl_cfi %ebp
     CFI_REL_OFFSET ebp, 0
     pushl_cfi %edi
     CFI_REL_OFFSET edi, 0
     pushl_cfi %esi
     CFI_REL_OFFSET esi, 0
     pushl_cfi %edx
     CFI_REL_OFFSET edx, 0
     pushl_cfi %ecx
     CFI_REL_OFFSET ecx, 0
     pushl_cfi %ebx
     CFI_REL_OFFSET ebx, 0
     movl $(__USER_DS), %edx
     movl %edx, %ds
     movl %edx, %es
     movl $(__KERNEL_PERCPU), %edx
     movl %edx, %fs
     SET_KERNEL_GS %edx
 .endm
 
主要作用就是将各个寄存器压入栈中。

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读