当前位置: 首页 > Linux

Linux系统调用

时间:2023-04-06 19:57:41 Linux

相关概念Programvsprocessvscommand:Linux系统上的所有操作都是由进程完成的,进程的运行是动态的。在此之前,它是一个静态程序。用户使用一个程序来启动一个进程。这个程序可以是别人写的(最后编译成可执行文件),比如ls、pwd、cat,也可以是我们自己写的。系统调用:不管怎样,程序最后都是作为一个进程运行的,程序要想在系统上运行,就需要用到系统调用,也就是系统提供给用户的API接口。trace命令:Linux有一个命令strace,常用来跟踪进程执行过程中的系统调用和接收到的信号。通过manstrace查看具体说明。Glibc:作为开发者,可能你不会直接使用系统调用,而是使用Glibc库。Glibc是Linux下使用的开源标准C库。它是GNU发布的libc库。Glibc是对系统调用的封装。介绍系统调用然后本文开始介绍这些系统调用。首先,上图中的进程管理linux操作系统使用fork从父进程创建子进程。子进程execve运行程序(二进制文件),父进程waitpid等待子进程结束。所有进程都是从父进程派生出来的。对于操作系统来说,始祖进程从何而来?系统启动时,首先创建一个所有用户进程的“祖先进程”。内存管理在操作系统中,每个进程都有自己的进程内存空间。其中,布局包括代码段、数据段、堆。一个进程的内存空间很大,32位是4G,64位更大。物理空间是有限的,所以进程空间不能提前分配,必须在需要的时候分配。brk和mmap是官方堆分配内存的系统调用。当分配的内存量比较少的时候,使用brk会和原来的堆数据连接起来。当分配的内存量比较大时,使用mmap会重新划分一块区域。文件管理文件系统相当于公司的数据库,用来保存一些永久性的数据。它可以保存很长时间。文件之所以能做到这一点,一方面是因为介质,另一方面是格式。对于文件操作,无非就是creatcreat,openingopen,readingread,writingwrite等。linux中一切都是文件,包括二进制文件,文本文件,stdout文件,socket文件,设备文件,目录文件,包括processesrunningin/proc下生成的进程号也是一个文件。Linux为每个文件分配一个文件描述符,它是一个整数。信号处理信号是一种针对紧急情况的异步处理机制。每个信号都有一个默认操作。当然,用户也可以自己编写信号处理函数,通过sigaction系统调用进行处理。进程间通信实现本地进程之间的数据互通。常见的处理机制包括消息队列和共享内存。通过msgget创建一个新队列,msgsnd将消息发送到消息队列,消息接收者可以使用msgrcv从队列中获取消息;我们可以通过shmget创建共享内存块,通过shmat将共享内存映射到自己的内存空间,然后就可以读写了。网络通信内核具有TCP/IP网络协议栈的实现,可以通过套接字实现跨系统的进程间通信。查看源码下载内核源码,找到./include/asm-x86_64/unistd.h文件,里面有系统调用的定义hinter@ubuntu:linux-2.6.11$head./include/asm-x86_64/unistd.h#ifndef_ASM_X86_64_UNISTD_H_#define_ASM_X86_64_UNISTD_H_#ifndef__SYSCALL#define__SYSCALL(a,b)#endif/**该文件包含系统调用号。*通过系统调用查看用户态到内核态的进程过程,用户态-系统调用-保存寄存器-在内核态执行系统调用-恢复寄存器-返回用户态。对于应用程序开发,上层还使用了glibc库(系统调用的封装库)。从glibc提供的open函数入手,分析如何从glibc的open调用到内核的sys_open!!!glibc包#下面的相关文件。/sysdeps/unix/syscalls.list#列出所有glibc函数对应的系统调用。/sysdeps/unix/make-syscalls.sh#根据上面的配置文件,对于每一个打包的系统调用,都会生成一个文件。/sysdeps/unix/syscall-template.S#定义了本次系统调用的调用方式。/sysdeps/hppa/sysdep.h#通过`vim-tPSEUDO`找到PSEUDO宏的定义。通过分析open函数的代码逻辑,得出任何系统调用都会调用DO_CALL。这也是一个宏,这个宏的定义对于32位和64位是不同的。32位系统调用进程继续分析glibc源码,发现在unix/sysv/linux/i386/sysdep.h中定义了宏DO_CALL。理解:用户调用通过软中断进入内核态,在系统调用表中找到对应的内核系统调用,在执行内核调用前保存用户态寄存器,执行内核调用后返回并恢复用户态。64位系统调用进程DO_CALL定义在源码位置unix/sysv/linux/x86_64/sysdep.h,或者将系统调用名转换成系统调用号放入寄存器rax中。和32位不同的是这里其实是调用的,不是中断,而是用syscall指令代替,传递参数的寄存器也变了。理解:用户通过syscall指令调入内核态,在系统调用表中找到对应的内核系统调用,在执行内核调用前保存用户态寄存器,执行内核调用后返回并恢复用户态。整个过程补充了arch/x86/entry/syscall_64.c中的系统调用表数据结构定义,系统调用列表输出在arch/x86/entry/syscalls/syscall_64.tbl#systemcallnumberabitypefunctionnamesystemcallname2commonopen在include/linux/syscalls.h中声明了sys_open系统调用函数声明,找到sys_open声明系统调用函数实现内核系统调用。实现与声明一致,fs/open.c编译规则接下来,在编译过程中,需要从syscall_32.tbl和syscall_64.tbl生成自己的unistd_32.h和unistd_64.h。arch/x86/entry/syscalls/Makefile文件中的引用Linux操作系统趣谈-05系统调用Linux系统趣谈专栏-09如何下载系统调用查看glibc源码glibc源码分析(1)在linux系统调用下实现一个系统调用