linux内核分析笔记----系统调用

使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 《Linux内核分析》笔记 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 《Linux内核分析》笔记内核态和系统调用操作系统将进程划分为内核态和用户态,用户的程序运行在用户态下,而涉及低级和设备资源的调用在内核态中完成。为了方便用户程序使用各种系统资源,操作系统为我们提供了系统调用,而避免用户之间操作各种系统资源所带来的隐患。实验原理使用系统调用的方式通常有使用库函数调用和中断传入系统调用号的方式两种。库函 阅读详情

      在Linux中,系统调用是用户空间访问内核的唯一手段,它们是内核唯一的合法入口。实际上,其他的像设备文件和/proc之类的方式,最终也还是要通过系统调用进行的。

       一般情况下,应用程序通过应用编程接口(API)而不是直接通过系统调用来编程,而且这种编程接口实际上并不需要和内核提供的系统调用对应。一个API定义了一组应用程序使用的编程接口。它们可以实现成一个系统调用,也可以通过调用多个系统调用来实现,即使不使用任何系统调用也不存在问题。实际上,API可以在各种不同的操作系统上实现,给应用程序提供完全相同的接口,而它们本身在这些系统上的实现却可能迥异。

       在Unix世界中,最流行的应用编程接口是基于POSIX标准的,Linux是与POSIX兼容的。

       从程序员的角度看,他们只需要给API打交道就可以了,而内核只跟系统调用打交道;库函数及应用程序是怎么使用系统调用不是内核关心的。

       系统调用(在linux中常称作syscalls)通常通过函数进行调用。它们通常都需要定义一个或几个参数(输入)而且可能产生一些副作用。这些副作用通过一个long类型的返回值来表示成功(0值)或者错误(负值)。在系统调用出现错误的时候会把错误码写入errno全局变量。通过调用perror()函数,可以把该变量翻译成用户可以理解的错误字符串。

       系统调用的实现有两个特别之处:1)函数声明中都有asmlinkage限定词,用于通知编译器仅从栈中提取该函数的参数。2)系统调用getXXX()在内核中被定义为sys_getXXX()。这是Linux中所有系统调用都应该遵守的命名规则。

       系统调用号:在linux中,每个系统调用都赋予一个系统调用号,通过这个独一无二的号就可以关联系统调用。当用户空间的进程执行一个系统调用的时候,这个系统调用号就被用来指明到底要执行哪个系统调用;进程不会提及系统调用的名称。系统调用号一旦分配就不能再有任何变更(否则编译好的应用程序就会崩溃),如果一个系统调用被删除,它所占用的系统调用号也不允许被回收利用。Linux有一个"未使用"系统调用sys_ni_syscall(),它除了返回-ENOSYS外不做任何其他工作,这个错误号就是专门针对无效的系统调用而设的。虽然很罕见,但如果有一个系统调用被删除,这个函数就要负责“填补空位”。

       内核记录了系统调用表中所有已注册过的系统调用的列表,存储在sys_call_table中。它与体系结构有关,一般在entry.s中定义。这个表中为每一个有效的系统调用指定了唯一的系统调用号。

       用户空间的程序无法直接执行内核代码。它们不能直接调用内核空间的函数,因为内核驻留在受保护的地址空间上,应用程序应该以某种方式通知系统,告诉内核自己需要执行一个系统调用,系统系统切换到内核态,这样内核就可以代表应用程序来执行该系统调用了。这种通知内核的机制是通过软中断实现的。x86系统上的软中断由int$0x80指令产生。这条指令会触发一个异常导致系统切换到内核态并执行第128号异常处理程序,而该程序正是系统调用处理程序,名字叫system_call().它与硬件体系结构紧密相关,通常在entry.s文件中通过汇编语言编写。

       所有的系统调用陷入内核的方式都是一样的,所以仅仅是陷入内核空间是不够的。因此必须把系统调用号一并传给内核。在x86上,这个传递动作是通过在触发软中断前把调用号装入eax寄存器实现的。这样系统调用处理程序一旦运行,就可以从eax中得到数据。上述所说的system_call()通过将给定的系统调用号与NR_syscalls做比较来检查其有效性。如果它大于或者等于NR_syscalls,该函数就返回-ENOSYS.否则,就执行相应的系统调用:call *sys_call_table(, %eax, 4);

       由于系统调用表中的表项是以32位(4字节)类型存放的,所以内核需要将给定的系统调用号乘以4,然后用所得到的结果在该表中查询器位置。如图图一所示:

                                      结构 

     上面已经提到,除了系统调用号以外,还需要一些外部的参数输入。最简单的办法就是像传递系统调用号一样把这些参数也存放在寄存器里。在x86系统上ebx,ecx,edx,esi和edi按照顺序存放前5个参数。需要六个或六个以上参数的情况不多见,此时,应该用一个单独的寄存器存放指向所有这些参数在用户空间地址的指针。给用户空间的返回值也通过寄存器传递。在x86系统上,它存放在eax寄存器中。

       系统调用必须仔细检查它们所有的参数是否合法有效。系统调用在内核空间执行。如果任由用户将不合法的输入传递给内核,那么系统的安全和稳定将面临极大的考验。最重要的一种检查就是检查用户提供的指针是否有效,内核在接收一个用户空间的指针之前,内核必须要保证:

1)指针指向的内存区域属于用户空间
2)指针指向的内存区域在进程的地址空间里
3)如果是读,读内存应该标记为可读。如果是写,该内存应该标记为可写。

       内核提供了两种方法来完成必须的检查和内核空间与用户空间之间数据的来回拷贝。这两个方法必须有一个被调用。

copy_to_user():向用户空间写入数据,需要3个参数。第一个参数是进程空间中的目的内存地址。第二个是内核空间内的源地址
                     .第三个是需要拷贝的数据长度(字节数)。
copy_from_user():向用户空间读取数据,需要3个参数。第一个参数是进程空间中的目的内存地址。第二个是内核空间内的源地
                     址.第三个是需要拷贝的数据长度(字节数)。
注意:这两个都有可能引起阻塞。当包含用户数据的页被换出到硬盘上而不是在物理内存上的时候,这种情况就会发生。此时,进程就会休眠,直到缺页处理程序将该页从硬盘重新换回到物理内存。

       内核在执行系统调用的时候处于进程上下文,current指针指向当前任务,即引发系统调用的那个进程。在进程上下文中,内核可以休眠(比如在系统调用阻塞或显式调用schedule()的时候)并且可以被抢占。当系统调用返回的时候,控制权仍然在system_call()中,它最终会负责切换到用户空间并让用户进程继续执行下去。

       给linux添加一个系统调用时间很简单的事情,怎么设计和实现一个系统调用是难题所在。实现系统调用的第一步是决定它的用途,这个用途是明确且唯一的,不要尝试编写多用途的系统调用。ioctl则是一个反面教材。新系统调用的参数,返回值和错误码该是什么,这些都很关键。一旦一个系统调用编写完成后,把它注册成为一个正式的系统调用是件琐碎的工作,一般下面几步:

1)在系统调用表(一般位于entry.s)的最后加入一个表项。从0开始算起,系统表项在该表中的位置就是它的系统调用号。如第
   10个系统调用分配到系统调用号为9
2)任何体系结构,系统调用号都必须定义于include/asm/unistd.h中
3)系统调用必须被编译进内核映像(不能编译成模块)。这只要把它放进kernel/下的一个相关文件就可以。

       通常,系统调用靠C库支持,用户程序通过包含标准头文件并和C库链接,就可以使用系统调用(或者使用库函数,再由库函数实际调用)。庆幸的是linux本身提供了一组宏用于直接对系统调用进行访问。它会设置好寄存器并调用int $0x80指令。这些宏是_syscalln(),其中n的范围是从0到6.代表需要传递给系统调用的参数个数。这是由于该宏必须了解到底有多少参数按照什么次序压入寄存器。以open系统调用为例:

open()系统调用定义如下是:
long open(const char *filename, int flags, int mode)
直接调用此系统调用的宏的形式为:
#define NR_open 5
_syscall3(long, open, const char *, filename, int , flags, int, mode)

    这样,应用程序就可以直接使用open().调用open()系统调用直接把上面的宏放置在应用程序中就可以了。对于每个宏来说,都有2+2*n个参数。每个参数的意义简单明了,这里就不详细说明了。

Linux内核分析(五)系统调用过程解析 本次的文章主要是继续讲解系统调用的过程,会更为详细的分析系统调用过程中的细节,包括进程调度的实际,实际服务程序的调用过程,现场的保存和恢复等等,与此同时简述了启动过程的调试以及实验过程。本次的文章中会着重为大家带来图解过程,希望可以更为清晰的看到这个系统调用的过程。 阅读详情

相关推荐

不用加速器!Google Earth Pro登录失败自救手册:从服务器连接到地图加载的完整排错流程

本文详细解析了Google Earth Pro登录失败的常见问题及解决方案,包括服务器连接失败、地图加载异常等。通过基础排查、内置修复工具使用和高级配置调整,帮助用户无需加速器即可解决启动问题、黑屏和转圈圈等困扰,提升软件使用体验。

weixin_29227425的博客 482

linux 系统调用流程分析

syscall指令会先查看此时RAX的值,然后找到系统调用号为那个值的系统调用,然后执行相应的系统调用。这就是让内核执行了fork。将所有寄存器压入内核栈,其中 ebx, ecx, edx 存放程序的参数以 eax 为偏移量,在 sys_call_table 中找到指定的系统调用的地址,其中sys_call_table 定义了所有的系统函数的地址。那么,编译出来的可执行程序会认为,这个函数是用户态函数,其传参仍然是按 %rdi, %rsi, %rdx, %rcx, %r8, %r9的顺序,与内核接口不符。

weixin_41028621的博客 1040

工业视觉光源频闪控制的三种核心模式与选型实战

本文深入解析工业视觉系统中光源频闪控制的三种核心模式:光源主控、相机主控与硬同步。针对高速飞拍、缺陷检测等场景,详细对比了各模式的时序原理、硬件要求与适用场景,并提供了基于产线速度与检测需求的实战选型指南,帮助工程师有效消除运动模糊、提升成像质量与系统稳定性。

weixin_29299807的博客 435

Linux--系统调用流程

在Linux中,每个进程都有一个私有的内核栈,当从用户栈切换到内核栈时,需完成保存%esp以及相关寄存器的值(%ebx,%ecx…Linux中,在用户态和内核态运行的进程使用的栈是不同的,分别叫做用户栈和内核栈, 两者各自负责相应特权级别状态下的函数调用。当进行系统调用时,进程不仅要从用户态切换到内核态,同时也要完成栈切换, 这样处于内核态的系统调用才能在内核栈上完成调用。计算机的各种硬件资源是有限的,为了更好的管理这些资源,用户进程是不允许直接操作的,所有对这些资源的访问都必须由操作系统控制。

qq_47258284的博客 2469

使用Termux在Android设备上编译运行SpecCPU2006

SPEC2006搭配Termux,竟然还能这么玩?!

菜菜的菜园子 2960

MT4/MT5数据源接入全攻略:从买服务、自研API到低成本DDE,哪种方案适合你?

本文全面解析MT4/MT5数据源接入的三种主流方案:商业服务、自研API和低成本DDE,详细对比其技术参数、成本结构和适用场景。帮助技术团队根据业务需求选择最优方案,确保外汇交易系统的数据流稳定性和实时性,提升交易体验和业务连续性。

weixin_42568801的博客 172

Linux 系统调用的执行过程

什么是系统调用 系统调用 (在 Linux 中常称为 syscalls ) 是应用程序访问硬件设备之间的桥梁。 系统调用层为用户空间提供一种硬件的抽象接口,使得用户不用关注设备的具体信息,同时系统调用保证了系统的稳定和安全。 在 Linux 中,除了异常和陷入外,系统调用是用户空间访问内核的唯一手段。 实际上,其他的像设备文件和 /proc 之类的方式,最终也还是要通过系统调用的方式进行访问。 系统调用号 在 Linux 中,每个系统调用被赋予一个系统调用号。通过这个独一无二的调用号就可以关联具体的系统调

qq_30192655的博客 4140

基于深度学习的柠檬等级检测系统 —— YOLOv8 + UI界面 + 数据集

本项目的目标是构建一个柠檬等级检测系统,通过深度学习模型自动检测柠檬的等级。自动检测柠檬等级:通过图像中的柠檬特征,自动判断其成熟度和质量。实时视频检测:通过摄像头实时监控柠檬的质量等级。用户友好的UI界面:为用户提供简洁直观的操作界面,支持图像上传、实时视频检测等功能。本项目展示了如何基于YOLOv8模型开发一个柠檬等级检测系统,结合PyQt5实现了用户友好的UI界面。通过该系统,用户可以快速上传柠檬图像并自动识别其等级,极大提升了检测效率和准确性。数据集的扩展。

YOLO 1111

Linux操作系统原理-系统调用理论详解

系统调用是一种特殊的函数调用,用于让用户空间的应用程序请求内核执行某些特权操作,例如文件操作、进程管理、网络通信等。系统调用是用户程序与操作系统内核之间的桥梁,它们允许用户程序访问底层硬件和操作系统提供的服务。

sinat_41393249的博客 1114

AUTOSAR模式管理-EcuM多核处理及其他概念

因此,EcuM不请求状态。因此,BswM必须确保,例如,在调用EcuM_GoHalt或EcuM_GoPoll之前,必须将关机目标从其默认值更改为ECUM_STATE_SLEEP。对于ECU的关闭,BswM(位于主EcuM的同一个分区中)最终调用主核上的GoOff,该GoOff将请求分发给所有的从核。在ECU Manager模块的早期版本中,睡眠目标被特殊处理,因为在ECU中实现的睡眠模式取决于ECU的功能。在使用了外部的SBC控制相关的MCU的下电的时候,在OFF阶段最后调用SBC进入到Sleep的指令。

m0_49148264的博客 1340

【100%通过率】华为OD机试真题 Java&Go 实现【水库蓄水问题】【2022.11 Q4 新题】

给定一个长度为 n 的整数数组height。数组的元素表示山的高度,选择两个元素作为水库的边界,求蓄水量的最大值并输出蓄水量最大时的边界下标(蓄水量相同时输出下标较近的)。

MISAYAONE的博客 1万+

Linux系统调用的过程

Linux系统调用的过程

qq_41583040的博客 1189

论文阅读 AIED 2024 Coding with AI: How Are Tools Like ChatGPT Being Used by Students in Foundational Pro

该论文题为《Coding with AI: How Are Tools Like ChatGPT Being Used by Students in Foundational Programming Courses》,由美国犹他州立大学的 Aashish Ghimire 与 John Edwards 共同撰写,发表于人工智能与教育领域顶级会议。

CSPhD-winston的博客 307

【Linux 内核源码分析笔记】系统调用

在Linux内核中,系统调用是用户空间程序与内核之间的接口,它允许用户空间程序请求内核执行特权操作或访问受保护的内核资源。系统调用提供了一种安全可控的方式,使用户程序能够利用内核功能而不直接访问底层硬件。

C/C++Linux、音视频、DPDK 1486

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Linux内核学习之 -- epoll()一族系统调用分析笔记

linux 4.19epoll()也是一种I/O多路复用的技术,但是完全不同于select()/poll()。更加高效,高效的原因其他博客也都提到了,这篇笔记主要是从源码的角度来分析一下实现过程。作为自己的学习笔记,分析都在代码注释中,后续回顾的时候看注释好一点。对于epoll()的分析建立在《Linux内核学习之 – 系统调用open()和write()的实现笔记》 + 《Linux内核学习之 – 系统调用poll()分析笔记》的基础上,因为有很多通用的步骤和环节。

xi_xix_i的博客 1417

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Linux内核学习之 -- 系统调用poll()分析笔记

第三步是系统调用重新执行相关的操作,涉及到系统调用退出时在entry.S中要执行的一个函数do_notify_resume(),该函数比较复杂,是否需要启动进程调度(need_reseched),是否重启系统调用,调试暂停(拦截内核的信号,暂停在这里并通知调试器)等都会在这里处理,暂时不进行分析,以后有空单独写一篇笔记。当唤醒之后,do_poll()会从休眠处继续运行,也就是会从poll_schedule_timeout()处继续运行(实际上是从调用schedule()的返回处继续运行)。

xi_xix_i的博客 1507

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Linux内核分析 笔记四 系统调用的三个层次 ——by王玥

一、知识点总结 (一)用户态、内核态和中断 1.内核态:在高的执行级别下,代码可以执行特权指令,访问任意的物理地址,这时的CPU就对应内核态 2.用户态:在低级别的指令状态下,代码 只能在级别允许的特定范围内活动。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。 3.在Linux下0级表示内核态,3级表示用户态。 4.内核态...

weixin_30516243的博客 254

《Linux内核分析》第四周笔记 扒开系统调用的三层皮(上)

扒开系统调用的三层皮(上) 一、用户态、内核态和中断   库函数将系统调用封装起来。   1、什么是用户态和内核态     一般现代CPU都有几种不同的指令执行级别。     在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态。     而在相应的低级别执行状态下(用户态),代码的掌控范围会受到限制。只能在对应级别允许的范围内活动。系统容易崩溃。...

weixin_30832143的博客 129

《Linux内核分析》第五周笔记 扒开系统调用的三层皮(下)

扒开系统调用的三层皮(下) 一、给menuOS增加time和time-asm   通过内核调试系统调用。将上次做的实验加入到menusOS,变成menusOS里面的两个命令。 1 int Getpid(int argc , char * argv[]) 2{ 3 int pid; 4 pid=getpid(); 5 printf("pid=%d\n",pid); 6 return ...

weixin_30674525的博客 115

Linux内核分析 笔记五 扒开系统调用的三层皮(下) ——by王玥

(一)给MenuOs增加time和time-asm命令 更新menu代码到最新版 在main函数中增加MenuConfig 增加对应的Ttime和TimeAsm函数 make rootfs (二)使用gdb跟踪系统调用内核函数sys_time 1.sys_time返回后进入汇编代码处理gdb无法继续跟踪 2.执行0x80之后执行system_call对...

weixin_30624825的博客 141

《Linux内核分析》 学习总结

摘要: 黄胤凯 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 学习笔记汇总: 《Linux内核分析》 第一节 计算机是如何工作的:http://www.cnblogs.com/20132109HKK/p/5225027.html 《Linux内核分析》 第二节 操作系统是如何工...

weixin_30723433的博客 82

Linux内核分析课程总结

Linux内核分析课程总结 By 20135203齐岳 知识梳理 (思维导图地址http://mindmap.4ye.me/mkxM0cFh/1) 从start _ kernel构造一个新的Linux内核开始,0号进程rest _ init创建了1号进程kernel _ init从而启动Linux内核,这个过程的中心思想其实一直贯穿在Linux内核操作系统之中。1号进程通过复制PCB创建出更多的...

weixin_34106122的博客 130

Linux内核分析期中总结

Linux内核分析期中总结 每周读书笔记链接汇总 第三周 http://www.cnblogs.com/lxq20135309/p/5284952.html 第四周 http://www.cnblogs.com/lxq20135309/p/5296846.html 第五周 http://www.cnblogs.com/lxq20135309/p/5335502.html 第六周 http://ww...

weixin_30758821的博客 83

linux内核系统调用和标准C库函数的关系分析

今天研究了一下系统调用和标准库函数的区别和联系,从网上搜集的资料如下: 资料引用分割线 《=================================================================================================================================》 1.系统调用是为了方便

做一个有技术追求的人 2万+

Linux 内核中的系统调用实现:从用户空间到内核空间

/ 自定义系统调用// 添加到系统调用表// 在 arch/x86/entry/syscalls/syscall_64.tbl 中添加:Linux 内核中的系统调用实现是用户空间与内核空间之间的桥梁,它允许应用程序访问内核提供的服务。系统调用的设计思路与企业管理中的接口设计有着密切的联系,它通过标准化接口、分层设计、安全性和可扩展性等机制,为应用程序提供了访问内核服务的统一方式。工作也要流程化,系统调用就像是系统中的接口规范,它确保了用户空间和内核空间的有序交互。

jiang_style的博客 3664
上一篇: 记住20句话,让自己变快乐
下一篇: linux内核分析笔记----进程管理
wustdatamining
博客等级 码龄15年 12粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值