linux编译内核及添加系统调用(1)

来源:互联网 时间:2026-02-26 16:23:18 作者:

系统大全为您提供
我们都知道系统功能调用是Unix/Linux操作系统向用户程序提供支持的接口,通过这些接口应用程序向操作系统请求服务,控制转向操作系统,而操作系统在完成服务后,将控制和结果返回给用户程序。   系统调用的主要目的是使得用户可以使用操作系统提供的有关设备管理、输入/输出系统、文件系统和进程控制、通信以及存储管理等方面的功能,而不必了解系统程序的内部结构和有关硬件细节,从而起到减轻用户负担和保护系统以及提高资源利用率的作用。   在进行系统功能调用时会由用户态(也称目态)转到核态(也称管态)。昨天我的一信安的朋友还问过我管态和目态的区别,我想来想去也就是这里有大的区别了,在管态下能使用系统的所有资源,调用系统的特权函数,而目态是不行的。在执行系统功能调用时就必须是在管态下执行。   而如果我需要给我的linux系统增加一个系统功能调用的话,就必须弄清楚系统是如何调用那些功能函数的,又是如何由目态变为管态的。在linux下可以通过中断来进入管态,这类中断称为访管中断。   内核中系统调用的过程   在Linux系统中,系统调用是作为一种异常类型实现的 ,它将执行相应的机器代码指令来产生异常信号。产生中断或异常的重要效果是系统自动将用户态切换为核心态来对它进行处理。   用户态的程序只有通过门(gate)陷入(trap)到系统内核中去(执行int指令),才能执行一些具有特权的内核函数。系统调用完成后,系统执行另一组特征指令(iret指令)将系统返回到用户态,控制权返回给进程。   Linux用来实现系统调用异常的实际指令是:   int $0x80   这一指令使用中断/异常向量号128(即16进制的80)将控制权转移给内核(进行模式切换)。   为达到在使用系统调用时不必用机器指令编程,在标准的C语言库中为每一系统调用提供了一段短的子程序,完成机器代码的编程工作。   事实上,机器代码段非常简短。它所要做的工作只是将送给系统调用的参数加载到CPU寄存器中,接着执行int $0x80指令。然后运行系统调用。   系统调用的返回值将送入CPU的一个寄存器中,标准的库子程序取得这一返回值,并将它送回用户程序。  下面以getuid()系统调用为例来看调用过程:

linux编译内核及添加系统调用(1)

 
我们可以看到其中有一些宏定义,我们可以看看这些宏的定义   (arch/i386/kernel/ entry.S).   ………   #define SAVE_ALL   cld;   pushl %es;   pushl %ds;   pushl %eax;   pushl %ebp;   pushl %edi;   pushl %esi;   pushl %edx;   pushl %ecx;   pushl %ebx;   movl $(__USER_DS),%edx;   movl %edx,%ds;   movl %edx,%es;   我们可以看到SAVE_ALL主要是保存寄存器信息,即现场保留。其中, movl $(__USER_DS), %edx;从这一句开始是重新填充DS,ES段。    #define RESTORE_INT_REGS   popl %ebx;   popl %ecx;   popl %edx;   popl %esi;   popl %edi;   popl %ebp;   popl %eax   #define RESTORE_REGS   RESTORE_INT_REGS;   1: popl %ds;   2: popl %es;   .section .fixup,"ax";   3: movl $0,(%esp);   jmp 1b;   4: movl $0,(%esp);   jmp 2b;   .previous;   .section __ex_table,"a";   .align 4;   .long 1b,3b;   .long 2b,4b;   .previous   ENTRY(ret_from_fork)   pushl %eax   call schedule_tail   GET_THREAD_INFO(%ebp)   popl %eax   jmp syscall_exit   这里主要完成现场恢复并返回。   ENTRY(system_call)   pushl %eax # save orig_eax   SAVE_ALL   GET_THREAD_INFO(%ebp)   # system call tracing in operation   /* Note, _TIF_SECCOMP is bit number 8, and so it needs testw and not testb */   testw $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP),TI_flags(%ebp)   jnz syscall_trace_entry   cmpl $(nr_syscalls), %eax   jae syscall_badsys   syscall_call:   call *sys_call_table(,%eax,4)   movl %eax,EAX(%esp) # store the return value   syscall_exit:   cli # make sure we don't miss an interrupt   # setting need_resched or sigpending   # between sampling and the iret   movl TI_flags(%ebp), %ecx   testw $_TIF_ALLWORK_MASK, %cx # current->work   jne syscall_exit_work   restore_all:   movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS   # Warning: OLDSS(%esp) contains the wrong/random values if we   # are returning to the kernel.   # See comments in process.c:copy_thread() for details.   movb OLDSS(%esp), %ah   movb CS(%esp), %al   andl $(VM_MASK | (4 << 8) | 3), %eax   cmpl $((4 << 8) | 3), %eax   je ldt_ss # returning to user-space with LDT SS   restore_nocheck:   RESTORE_REGS   addl $4, %esp   1: iret   这一段中,主要是完成调用。eax放置的是系统调用号 ,因为eax有可能被使用,所以先保存其值。call *sys_call_table(,%eax,4) 这一句是计算调用的入口。   其中,sys_call_table是LINUX的系统调用表,它存在目录arch/i386/kernel/ sys_call_table.S 下。   .data   ENTRY(sys_call_table)   .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */   .long sys_exit   .long sys_fork   .long sys_read   .long sys_write   .long sys_open /* 5 */   ……   ……   .long sys_mq_timedreceive /* 280 */   .long sys_mq_notify   .long sys_mq_getsetattr   .long sys_ni_syscall /* reserved for kexec */   .long sys_waitid   .long sys_ni_syscall /* 285 */ /* available */  
  以上就是系统大全给大家介绍的如何使的方法都有一定的了解了吧,好了,如果大家还想了解更多的资讯,那就赶紧点击系统大全官网吧。 
 
本文来自系统大全https://www.herecours.com/d/file/efpub/2026/26-26/20260226160450569478

相关推荐

热文推荐