关于linux:Linux系统调用

相干概念

程序vs过程vs命令: Linux零碎上所有的操作由过程实现,过程的运行是动静的,在此之前是一个动态的程序。用户用一个程序来启动一个过程,这个程序能够是他人写好的(最终被编译成可执行文件),比方lspwdcat,也能够是咱们本人写的。
零碎调用: 无论如何,程序最初运行起来都是过程,并且一个程序想要在零碎上跑,要用到零碎调用,这是零碎给用户提供的API接口。
trace命令: Linux有个命令strace,罕用来跟踪过程执行时零碎调用和所接管的信号。通过manstrace查看具体形容。
Glibc: 作为一个开发者,兴许平时并没有间接应用零碎调用,而是Glibc库。Glibc是Linux下应用的开源的规范C库它是GNU公布的libc库。Glibc即零碎调用的封装。

介绍零碎调用

而后本文开始介绍这些零碎调用,先上图

过程治理

linux操作系统应用fork从父过程中创立子过程,子过程execve运行程序(二进制文件),父过程waitpid期待子过程完结。
所有过程都是父过程fork进去的,对于操作系统而言第一个鼻祖过程是哪来的呢? 系统启动的时候先创立一个所有用户过程的“祖宗过程”。

内存治理

在操作系统中,每个过程都有本人的过程内存空间。其中布局就有代码段数据段
一个过程的内存空间是很大的,32位的是4G,64位的就更大了。物理空间是无限的,所以过程的空间不能当时调配好的,肯定是须要的时候再调配。
brkmmap是官员堆分配内存的零碎调用,分配内存数量比拟小的时候,应用brk会和原来的堆的数据连在一起。当调配的内存数量比拟大的时候,应用mmap,会从新划分一块区域。

文件治理

文件系统相当于公司的资料库,用于保留一些永恒性质的数据。能做到长期保留,文件之所以能做到这一点,一方面是因为介质,另一方面是因为格局
对于文件的操作,无非是创立creat关上open读read写write等等
Linux中所有皆文件就包含二进制文件文本文件stdout文件Socket文件设施文件目录文件,包含过程运行起来在/proc下生成的过程号也是文件。对于每一个文件,Linux调配了文件描述符,这是一个整数。

信号处理

信号是异步解决机制,用于紧急突发状况。每一种信号都有默认动作,当然用户也能编写信号处理函数,通过sigaction零碎调用进行解决。

过程间通信

本地过程之间实现数据的互通,比拟常见的解决机制有音讯队列共享内存
通过msgget创立一个新的队列,msgsnd将音讯发送到音讯队列,而音讯接管方能够应用msgrcv从队列中取音讯; 咱们能够通过shmget创立一个共享内存块,通过shmat将共享内存映射到本人的内存空间,而后就能够读写了。

网络通信

内核中有TCP/IP网络协议栈的实现,能够通过socket来实现跨零碎的过程间通信。

查看源码

下载内核源码,找到./include/asm-x86_64/unistd.h文件,外面对于零碎调用的定义

hinzer@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

/*
 * This file contains the system call numbers.
 *

查看过程

过程通过零碎调用从用户态到内核态,用户态 - 零碎调用 - 保留寄存器 - 内核态执行零碎调用 - 复原寄存器 - 返回用户态。对于利用开发,下层还通过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 -t PSEUDO` 找到 PSEUDO 这个宏的定义。

通过剖析: open函数的代码逻辑,得出结论: 对于任何的零碎调用,会调用DO_CALL。这也是一个宏,这个宏 32 位和 64 位的定义是不一样的。

32位零碎调用过程

持续剖析glibc源码,发现宏DO_CALL定义处unix/sysv/linux/i386/sysdep.h
了解: 用户调用通过软中断进入内核态,在零碎调用表中找到对应的内核零碎调用,执行内核调用之前保留用户态寄存器,执行内核调用后返回并复原用户态。

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

#零碎调用号 abi类型 函数名                      零碎调用名
2       common  open                    sys_open
零碎调用函数申明

申明在include/linux/syscalls.h,找到有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源码剖析(一)零碎调用
  • linux下实现一个零碎调用

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理