linux 系统调用流程分析

  • x86

1.系统调用

  系统调用是用户空间程序与内核交互的主要机制。系统调用与普通函数调用不同,因为它调用的是内核里的代码。使用系统调用时,需要特殊指令以使处理器权限转换到内核态。另外,被调用的内核代码由系统调用号来标识,而不是函数地址。系统调用流程如下图所示:
在这里插入图片描述

2.x86 系统调用实现原理

  比如创建子进程,内核提供fork系统调用作为接口。如果用户态程序想调用这个内核提供的接口,其对应的汇编语句

movq $57, %rax
syscall

  syscall指令会先查看此时RAX的值,然后找到系统调用号为那个值的系统调用,然后执行相应的系统调用。在系统调用列表中找到,fork这个系统调用的系统调用号是57。于是,把57放入rax寄存器中,然后使用了syscall指令。这就是让内核执行了fork。

2.1.调用约定

  系统调用往往会有许多参数,比如说open系统操作,在include/linux/syscalls.h中找到其对应的C语言接口为

asmlinkage long sys_open(const char __user *filename, int flags, umode_t mode);

  它接受三个参数。那么,参数传递是按照什么规定呢?事实上,当涉及到系统调用时,调用约定与用户态程序一般的调用约定并不相同。x86-64 ABI文档 第A.2.1节,描述了调用约定:

The Linux AMD64 kernel uses internally the same calling conventions as user-level applications (see section 3.2.3 for details). User-level applications that like to call system calls should use the functions from the C library. The interface between the C library and the Linux kernel is the same as for the user-level applications with the following differences:User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9.A system-call is done via the syscall instruction. The kernel clobbers registers %rcx and %r11 but preserves all other registers except %rax.The number of the syscall has to be passed in register %rax.System-calls are limited to six arguments, no argument is passed directly on the stack.Returning from the syscall, register %rax contains the result of the system-call. A value in the range between -4095 and -1 indicates an error, it is -errno.Only values of class INTEGER or class MEMORY are passed to the kernel.

  可以看出,系统调用约定了以下几个方面:

  • 参数相关
  • 系统调用号
  • 系统调用指令
  • 返回值及错误码

  这个规范就称为内核接口的调用约定,可以从第一点就显著地看到,这个调用约定与用户态的程序是不同的。也就是说,如果我们用编译器直接编译

long sys_open(const char *pathname, int flags, mode_t mode);

  那么,编译出来的可执行程序会认为,这个函数是用户态函数,其传参仍然是按 %rdi, %rsi, %rdx, %rcx, %r8, %r9的顺序,与内核接口不符。因此,gcc提供了一个标签asmlinkage来标记这个函数是内核接口的调用约定:

asmlinkage long sys_open(const char *pathname, int flags, mode_t mode);

  当函数前面有这个标签时,编译器编译出的可执行程序就会认为是按内核接口的调用约定对这个函数进行调用的。

2.1 系统调用的入参

2.1.1 参数顺序
在这里插入图片描述
对应关系查看arch/x86/entry/entry_64.S:

 435 /*436  * System call entry. Upto 6 arguments in registers are supported.437  *438  * SYSCALL does not save anything on the stack and does not change the439  * stack pointer.440  */441442 /*443  * Register setup:444  * rax  system call number445  * rdi  arg0446  * rcx  return address for syscall/sysret, C arg3447  * rsi  arg1448  * rdx  arg2449  * r10  arg3  (--> moved to rcx for C)450  * r8   arg4451  * r9   arg5452  * r11  eflags for syscall/sysret, temporary for C453  * r12-r15,rbp,rbx saved by C code, not touched.454  *455  * Interrupts are off on entry.456  * Only called from user space.457  *458  * XXX  if we had a free scratch register we could save the RSP into the stack frame459  *      and report it properly in ps. Unfortunately we haven't.460  *461  * When user can change the frames always force IRET. That is because462  * it deals with uncanonical addresses better. SYSRET has trouble463  * with them due to bugs in both AMD and Intel CPUs.464  */

2.1.2 参数数量

  系统调用参数限制为6个。

2.1.3 参数类型

  参数类型限制为 INTEGER 和 MEMORY。x86-64 ABI 定义第3.2.3节 Parameter Passing描述:

INTEGER This class consists of integral types that fifit into one of the general purpose registers.
MEMORY This class consists of types that will be passed and returned in memory via the stack.

2.2 返回值及错误码
  当从系统调用返回时,%rax里保存着系统调用结果;如果是-4095 至 -1之间的值,表示调用过程中发生了错误。

2.3 系统调用号

  系统调用号通过%rax传递。

2.4 系统调用指令

  系统调用通过指令syscall来执行。

3.将中断号与系统调用函数绑定

  系统调用函数 (system_call) 是系统调用的总入口,将其与中断号 0x80绑定。

arch/x86/kernel/traps.c
#define SYSCALL_VECTOR 0x80
set_system_trap_gate(SYSCALL_VECTOR, &system_call);

3.1.系统调用函数实现

  比如创建子进程,内核提供fork系统调用作为接口。如果用户态程序想调用这个内核提供的接口,其对应的汇编语句

movq $57, %rax
syscall

  syscall指令会先查看此时RAX的值,然后找到系统调用号为那个值的系统调用,然后执行相应的系统调用。在系统调用列表中找到,fork这个系统调用的系统调用号是57。于是,把57放入rax寄存器中,然后使用了syscall指令。这就是让内核执行了fork。

  由于需要从用户态栈切换到内核态栈,需要栈切换,因此CPU会将用户态的栈相关的参数(oldss, oldesp)压栈,再调用system_call。

  在 system_call 内部:

  将所有寄存器压入内核栈,其中 ebx, ecx, edx 存放程序的参数以 eax 为偏移量,在 sys_call_table 中找到指定的系统调用的地址,其中sys_call_table 定义了所有的系统函数的地址。

从以上可以看出参数传递的方式:

  • 从用户态到内核态通过寄存器传递
  • 内核函数通过栈读取,即通过栈传递
arch/x86/kernel/entry_32.S
.macro SAVE_ALLcldPUSH_GSpushl %fspushl %espushl %dspushl %eaxpushl %ebppushl %edipushl %esipushl %edxpushl %ecxpushl %ebxmovl $(__USER_DS), %edxmovl %edx, %dsmovl %edx, %esmovl $(__KERNEL_PERCPU), %edxmovl %edx, %fsSET_KERNEL_GS %edx
.endmENTRY(system_call)pushl %eax			# save orig_eaxSAVE_ALLGET_THREAD_INFO(%ebp)		# system call tracing in operation / emulationtestl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)jnz syscall_trace_entrycmpl $(nr_syscalls), %eaxjae syscall_badsys
syscall_call:call *sys_call_table(,%eax,4)movl %eax,PT_EAX(%esp)		# store the return value

arch/x86/kernel/syscall_table_32.S:

ENTRY(sys_call_table).long sys_restart_syscall	/* 0 - old "setup()" system call, used for restarting */.long sys_exit.long ptregs_fork.long sys_read.long sys_write.long sys_open		/* 5 */.long sys_close....long sys_rt_tgsigqueueinfo	/* 335 */.long sys_perf_event_open.long sys_recvmmsg.long sys_fanotify_init.long sys_fanotify_mark.long sys_prlimit64		/* 340 */

refer to

  • https://juejin.cn/post/7203681024236355639
  • https://wenfh2020.com/2021/09/05/kernel-syscall/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/200269.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

树与二叉树堆:堆

堆的概念: 一般是把数组的数据在逻辑结构上看成一颗完全二叉树,如下图所示。 注意:别将C语言中的堆和数据结构的堆混为一谈,本文所讲的数据结构的堆是一种完全二叉树,而C语言中的堆其实是一种内存区域的划分 堆的分类…

VMware——WindowServer2012R2环境安装mysql5.7.14解压版_互为主从(图解版)

目录 一、服务器信息二、192.168.132.35服务器上安装mysql(主)2.1、环境变量配置2.2、安装2.2.1、修改配置文件内容2.2.2、初始化mysql并指定超级用户密码2.2.3、安装mysql服务2.2.4、启动mysql服务2.2.5、登录用户管理及密码修改2.2.6、开启远程访问 三…

docker更换国内源

docker更换国内源 1、编辑Docker配置文件 在终端中执行以下命令,编辑Docker配置文件: vi /etc/docker/daemon.json2、添加更新源 在打开的配置文件中,添加以下内容: {"registry-mirrors": ["https://hub-mirror…

gitlab环境准备

1.准备环境 gitlab只支持linux系统,本人在虚拟机下使用Ubuntu作为操作系统,gitlab镜像要使用和操作系统版本对应的版本,(ubuntu18.04,gitlab-ce_13.2.3-ce.0_amd64 .deb) book100ask:/$ lsb_release -a No LSB modules are available. Dist…

03-瑞吉外卖关于菜品/套餐分类表的增删改查

新增菜品/套餐分类 页面原型 当我们在后台系统中添加菜品/套餐时,需要选择一个菜品/套餐分类,在移动端也会按照菜品分类和套餐分类来展示对应的菜品和套餐 第一步: 用户点击确定按钮执行submitForm函数发送Ajax请求,将新增菜品/套餐表单中输入的数据以json形式提交给服务端,…

算法分析与设计课后练习22

设W(5,7,10,12,15,18,20)和M35,使用过程SUMOFSUB找出W种使得和数等于M的全部子集并画出所生成的部分状态空间树

CV计算机视觉每日开源代码Paper with code速览-2023.11.16

点击CV计算机视觉,关注更多CV干货 论文已打包,点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构】ConvNet vs Transformer, Supervised vs CLIP: Beyond ImageNet Accuracy 论文地址:https://arxiv.org//pdf/23…

数据分析思维与模型:多维度拆解分析法

多维度拆解分析法"(Multi-Dimensional Analysis and Decomposition Method)是一种用于深入分析和解决复杂问题的方法论。这种方法侧重于从多个角度或维度来考察问题,以便于更全面地理解和解决它们。它通常包括以下几个步骤: …

环保回收信息展示预约小程序的效果如何

人们每天在线上的时间非常多,他们会通过线上寻找信息,而环保回收企业也在通过线上寻找客户,但受限于平台限制,无论引流获客还是营销互动、或是数据分析及全面管理方面都面对难题,其中微信/百度/快手/抖音/支付宝/快手等…

我在CSDN开组会1-蒙特卡洛模拟在矿床学的应用展望

各位老师、同学们,大家好。今天组会的内容是蒙特卡洛模拟在矿床学的应用展望。 为什么要讲蒙特卡洛模拟呢,因为我发现在地质学方面已经有不少应用,但是蒙特卡洛模拟延伸的知识太晦涩了,劝退了很多探究者们。因此,计划…

DSP介绍及CCS

文章目录 CCS版本编译器CCS使用注意严禁中文 CCS的基本操作新建工程导入现有工程调整字体的大小工程界面恢复标签的使用 仿真盒小虫子进入在线Debug 芯片TMS320F28355基本介绍特性 DSP中特殊指令dsp指令中的EALLOW EDIS CCS TI官网 版本 CCS版本: CCS8.3.1.0004_…

腾讯云HAI域AI作画

目录 🐳前言: 🚀了解高性能应用服务 HAI 👻即插即用 轻松上手 👻横向对比 青出于蓝 🐤应用场景-AI作画 🐤应用场景-AI对话 🐤应用场景-算法研发 🚀使用HAI进行…

Web 自动化神器 TestCafe—页面基本操作篇

前 言 Testcafe是基于node.js的框架,以操作简洁著称,是web自动化的神器 今天主要给大家介绍一下testcafe这个框架和页面元素交互的方法。 一、互动要求 使用 TestCafe 与元素进行交互操作,元素需满足以下条件:☟ 元素在 body 页…

怎么让NetCore接口支持Json参数

项目:NetCore Web API 接口支持Json参数需要安装Newtonsoft.Json.Linq和Microsoft.AspNetCore.Mvc.NewtonsoftJson Program代码 //支持json需要安装Microsoft.AspNetCore.Mvc.NewtonsoftJson using Newtonsoft.Json.Serialization;var builder WebApplication.Cr…

【Seata源码学习 】篇三 TM开启全局事务的过程

【Seata源码学习 】篇三 TM开启全局事务的过程 TM发送 单个或批量 消息 以发送GlobalBeginRequest消息为例 TM在执行拦截器链路前将向TC发送GlobalBeginRequest 消息 io.seata.tm.api.DefaultGlobalTransaction#begin(int, java.lang.String) Overridepublic String begin(…

媲美有线操作,支持4KHz响应和无线充电的游戏鼠标,雷柏VT3S上手

对于无线鼠标来说,操作延迟和精度对游戏操作影响很大,常见的游戏鼠标至少都有1KHz的回报率,而雷柏今年已经出了很多支持4KHz回报的鼠标了,像是我现在用的这款VT3S游戏鼠标,就搭载了旗舰级的原相3395引擎,支…

git撤销未git commit的文件

目录 一、问题描述 二、方式1:git命令撤销(更专业) 1、文件已git add,未git commit 2、本地修改,未git add (1)撤销处于unstage的文件,即删除已有变动 (2&#xff…

netty整合websocket(完美教程)

websocket的介绍: WebSocket是一种在网络通信中的协议,它是独立于HTTP协议的。该协议基于TCP/IP协议,可以提供双向通讯并保有状态。这意味着客户端和服务器可以进行实时响应,并且这种响应是双向的。WebSocket协议端口通常是80&am…

一些损失函数的学习

CrossEntropy loss 交叉熵是用来衡量两个概率分布之间的差异性或不相似性的度量交叉熵定义为两个概率分布p和q之间的度量。其中,p通常是真实分布,而q是模型预测的分布 交叉熵还等于信息熵 相对熵 这里,x遍历所有可能的事件,p(x)…

Window下如何对Redis进行开启与关闭

目录 前言1. 图文界面2. 命令行 前言 由于长期使用Linux界面,对于Window下的Redis,不知如何下手。特此记录该博文 特别注意,刚下载好的Redis,如果需要配置密码,可以再该文件进行配置:redis.windows-servi…