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.mzph.cn/news/156538.shtml

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

相关文章

上门维修安装派单系统小程序APP开发之会员级别设计深度解析

啄木鸟鲁班大师上门安装维修平台APP开发之VIP会员解析,在APP或者小程序里设置的会员叫VIP级别会员,系统一共分为4种会员,注册会员,正式会员,VIP金卡会员,VIP钻卡会员。注册用户是指注册了平台但是没有消费记…

预计2023年交付35万台,增速超400%!HUD硬核玩家强势崛起

随着HUD市场渗透率加速提升,其高速增长期已经来临。 W-HUD和AR-HUD在中国市场的萌芽导入期是在2020年前后,此前HUD市场不温不火,主要归因于以往W-HUD FOV较小,成像画面有限,显示内容简单且效果粗糙;而AR-H…

Linux下使用宏定义判断系统架构和系统类型

文章目录 查看编译器当前支持的宏定义查找指定的宏不同架构不同系统 附录-编译器内部常用的一些宏定义宏定义实际应用使用宏定义判断系统架构使用宏定义判断系统类型 一般情况下在linux下做C/C方面的开发不需要太关注系统架构,当然如果涉及到不同架构下的适配问题&a…

软考小记-软件工程

模块的控制范围包括模块本身及其所有的从属模块。模块的作用范围是指模块一个判定的作用范围,凡是受这个判定影响的所有模块都属于这个判定的作用范围.,原则上一个模块的作用范围应该在其控制范围之内,若没有,则可以将判定所在模块…

安装向量数据库milvus及其Attu

前置条件安装docker compose 在宿主机上创建文件目录 mkdir -p /home/sunyuhua/milvus/db mkdir -p /home/sunyuhua/milvus/conf mkdir -p /home/sunyuhua/milvus/etcd下载docker-compose.yml wget https://github.com/milvus-io/milvus/releases/download/v2.2.11/milvus-s…

OpenGL_Learn14(光照贴图)

1. 漫反射贴图 在光照场景中,它通常叫做一个漫反射贴图(Diffuse Map)(3D艺术家通常都这么叫它),它是一个表现了物体所有的漫反射颜色的纹理图像。 我们会将纹理储存为Material结构体中的一个sampler2D 。我们将之前定义的vec3漫反…

AI技术实力认证,宏电股份荣获2023年度AI天马“领军企业”

近日,由中国新一代人工智能发展战略研究院指导,深圳市人工智能产业协会主办,广东未来产业研究院承办的2023年度“AI天马”认定最终结果公布,宏电股份荣获AI天马“领军企业”奖项。 宏电股份基于20余年的技术沉淀,在工业…

基于猎食者算法优化概率神经网络PNN的分类预测 - 附代码

基于猎食者算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于猎食者算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于猎食者优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神经网络…

关于lenra你需要了解的

monorepo:项目代码管理方式,单个仓库中管理多个项目是一种设计思想 lenra:是一种工具,对于使用npm和git管理多软件包代码仓库的工作流程进行优化 使用这些工具的优点: 公共依赖只要安装一次,Monorepo 中…

数字化转型导师坚鹏:数字化时代银行网点厅堂营销5大关键点分析

数字化时代银行网点厅堂营销需要抓住以下5大关键点: 1、精准识别客户:在数字化时代,银行网点厅堂营销的关键在于精准识别客户。通过利用大数据和人工智能技术,银行可以分析客户的行为和需求,从而更好地了解客户&#…

面试题:你怎么理解System.out.println() ?

文章目录 首先分析System源码out源码分析println分析拓展知识点 你如何理解System.out.println() ? 学了这么久的面向对象编程,那如何用一行代码体现呢? 如果你能自己读懂System.out.println(),就真正了解了Java面向对象编程的含义 面向对…

如何理解低代码开发工具?

目录 一、低代码平台是什么 1. 数据输入 2. 数据流转 3. 数据加工 4. 数据输出 (1)视图:单表的数据的简单展示 (2)看板:提供单表、多表数据的多种图表组合展示 二、低代码能力 ➪ 全栈可视化编程&#xff1…

大彻大悟,期末的大学生请码住!!

不装了,我摊牌了,这东西大学生太太太需要了啊! 就是这个 写作火火,只需要输入需求,一键生成,几秒就给我写出来一篇,不满意还可以重新写,关键每次内容都不一样,完全不怕…

Redis常用的八种场景

作为一名 Java后端人员,对 Redis肯定并不陌生,Redis作为一种内存数据库,以其速度之快在编程的舞台上纵横多年,那么,Redis到底适合哪些业务场景?今天就来聊一聊。 1. 缓存/数据库 缓存(Cache&am…

电压放大器实验可以研究哪些领域

电压放大器是一种电子电路,能够对输入信号进行放大,使得输出信号具有更大的幅度。在实验中,电压放大器可以应用于许多领域,从电子学到通信领域,都能够进行研究与实践。 在电子学领域,电压放大器实验可以用于…

算法---腐烂的橘子

题目 在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一: 值 0 代表空单元格; 值 1 代表新鲜橘子; 值 2 代表腐烂的橘子。 每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回 直到单元格…

STM32在进行CAN总线多节点通信时,同时发数据会一直收不到某设备数据的问题及解决

CAN多设备通信收不到某设备数据的问题及解决 遇到的问题问题的发现CAN总线的一般冲突机制STM32中的CAN冲突机制 遇到的问题 问题的发现 最近在开发Canopen项目中,进行一主多从设备通信时,主站发送同步帧,两个从站往往只有帧ID优先级高的设备…

【C++进阶之路】第四篇:set和map

文章目录 一、关联式容器健值对二、set & multiset三、map & multimap在这里插入图片描述 四、set和map底层原理 一、关联式容器健值对 关联式容器 & 键值对 二、set & multiset set & multiset 三、map & multimap map & multimap 四、set和…

SocketIo的使用和基于SocketIO的聊天室

Socket.IO 是一个库,可以在客户端和服务器之间实现 低延迟, 双向 和 基于事件的 通信。 一、Socket.IO的特点 以下是 Socket.IO 在普通 WebSockets 上提供的功能: 1、HTTP 长轮询回退 如果无法建立 WebSocket 连接,连接将回退到 HTTP 长轮…