当前位置: 首页 > news >正文

Linux 触发用户态到内核态切换的是:系统调用、中断与异常

此文是 ChatGPT 生成的文章,帮助理解 : 用户态什么时候会切换到内核态

在 Linux 中,程序平时运行在用户态,而内核代码运行在内核态。很多人会把“切换到内核态”理解成“用户程序一调用函数就进内核了”,其实不是。真正会触发用户态到内核态切换的,是系统调用、中断和异常

一、什么是切换到内核态

CPU 运行程序时,会处在不同的权限级别。
用户程序运行在低权限的用户态,不能直接操作硬件,也不能直接执行内核函数。
当程序需要操作文件、申请内存、访问设备、等待输入输出时,就必须通过受保护的入口进入内核,由内核代为完成。

这个过程就是:

用户态 → 内核态 → 返回用户态

二、不是“调用函数就切换”,而是“发生特定事件才切换”

很多常见函数名看起来像是在做系统级事情,比如:

  • printf()
  • malloc()
  • memcpy()

但它们本身不一定会切换到内核态

它们通常先在用户态完成自己的工作,只有在内部确实需要内核帮助时,才会发起系统调用,进入内核态。

例如:

  • malloc()先尝试在用户堆里分配
  • 不够时才通过brk()mmap()向内核申请更多空间
  • 这时才发生用户态到内核态切换

三、最常见的切换方式:系统调用

用户程序不能直接调用内核内部函数,必须通过系统调用进入内核。

例如:

  • read()
  • write()
  • open()
  • ioctl()
  • fork()
  • mmap()

这些函数的最终路径,都会经过系统调用入口。

系统调用的过程大致是:

  1. 用户程序调用 libc 接口(这里的libc ,一般指 C 运行时库,也就是常说的 C 标准库 / 标准库实现,在 Linux 上最常见的是 glibc,也可能是 uClibc、musl。它不只是 C 语言标准里的那些函数,还包括很多POSIX 接口的封装

比如:

  • printf()
  • malloc()
  • free()
  • strlen()
  • strcpy()
  • fopen()
  • fread()
  • fwrite()
  • open()
  • read()
  • write()

其中有些是纯库函数,有些是对系统调用的封装。

2. libc 发现需要进入内核

3. 通过syscallint 0x80svc等指令触发切换

4. CPU 进入内核态

5. 内核执行对应服务函数

6. 返回用户态

四、除了系统调用,中断和异常也会切换到内核态

1. 中断

比如:

  • 定时器中断
  • 键盘中断
  • 网卡中断
  • 设备中断

硬件一旦发出中断,CPU 会暂停当前用户程序,转去执行内核中的中断处理代码。

2. 异常

比如:

  • 缺页异常(page fault)
  • 除零异常
  • 非法指令异常

当程序访问了尚未映射的内存页,CPU 也会进入内核,由内核处理缺页,再返回用户态继续执行。

五、以 malloc() 为例理解切换过程

#include <stdio.h> #include <stdlib.h> int main() { int *p = malloc(100); printf("%p\n", p); free(p); return 0; }

这个程序里,malloc(100)表面上只是一个普通函数,但它内部可能分两种情况:

情况一:用户堆里还有空闲内存

malloc()直接从用户态的内存管理器中分配,不进入内核态

情况二:用户堆不够了

malloc()会通过系统调用向内核申请更多空间,例如:

  • brk()
  • mmap()

这时 CPU 才会:

  • 从用户态切换到内核态
  • 内核扩展进程虚拟地址空间
  • 返回用户态
  • malloc()再把结果交给程序

所以,malloc 本身不一定切换内核态,只有在需要向内核要资源时才会切换

六、用户态与内核态各自使用自己的栈

用户栈

  • 每个线程有自己的用户栈
  • 保存函数调用、局部变量、返回地址
  • 程序结束时由内核自动回收

内核栈

  • 每个线程进入内核态时使用自己的内核栈
  • 空间较小,通常只有几 KB 到十几 KB
  • 不能随便放大数组或大对象

也就是说,切换到内核态时,不只是权限变了,连使用的栈也变了

七、 可以这样记忆

用户程序并不是“想进内核就能进内核”,而是必须通过正规入口:

  • 系统调用:最常见
  • 中断:硬件触发
  • 异常:错误或缺页触发

而普通的用户态函数调用,大多数仍然是在用户空间内部完成。

八、一句话总结

用户态切换到内核态,发生在系统调用、中断和异常这些受保护事件中;像malloc()printf()这类函数本身不一定切换,只有它们内部需要内核服务时,才会真正进入内核态。

--------------------------------------------------------------------------------------------------------------------

下面是补充的知识点:

1.libc,一般指C 运行时库,也就是常说的C 标准库 / 标准库实现,在 Linux 上最常见的是glibc,也可能是 uClibc、musl。

它不只是 C 语言标准里的那些函数,还包括很多POSIX 接口的封装

比如:

  • printf()
  • malloc()
  • free()
  • strlen()
  • strcpy()
  • fopen()
  • fread()
  • fwrite()
  • open()
  • read()
  • write()

其中有些是纯库函数,有些是对系统调用的封装。

2. libc 接口和系统调用是什么关系?

可以简单理解成这样:

用户程序 → libc 接口 → 系统调用 → 内核

但要注意:

  • 不是所有 libc 函数都会进入内核
  • 只有需要内核服务时,才会触发系统调用

例子

printf()

大多数时候只是,用户态库函数,先把内容放到缓冲区里。
真正写到终端或文件时,可能才会调用write(),进而进入内核。

malloc()

先由 libc 自己管理堆内存。
如果不够了,才会调用brk()mmap()之类的系统调用。

3. 系统调用指的是什么?

系统调用是用户态 请求 内核服务 的入口
用户程序不能直接执行内核代码,必须通过系统调用。

常见系统调用有很多,按功能大致可以分成几类:

文件和目录相关

  • open
  • close
  • read
  • write
  • lseek
  • stat
  • unlink
  • rename

进程管理相关

  • fork
  • vfork
  • execve
  • exit
  • waitpid
  • getpid
  • kill

内存管理相关

  • brk
  • mmap
  • munmap
  • mprotect

设备和控制相关

  • ioctl

时间相关

  • nanosleep
  • clock_gettime
  • gettimeofday

网络相关

  • socket
  • bind
  • listen
  • accept
  • connect
  • send
  • recv

事件等待相关

  • select
  • poll
  • epoll_create
  • epoll_ctl
  • epoll_wait

4. 一个很重要的区别:库函数不等于系统调用

例如:

  • printf()库函数
  • write()才是更接近内核的接口
  • write()最终会触发系统调用

再比如:

  • malloc()是库函数
  • brk()/mmap()才会进入内核

所以可以记成:

libc 是“用户态工具箱”,系统调用是“进入内核的门”。

5. 最容易混淆的一点

有些函数名字看起来像系统调用,但其实你平时调用的往往是libc 封装后的版本

比如:

int fd = open("a.txt", O_RDONLY);

你写的是open(),但它通常是 libc 提供的包装,内部再调用系统调用进入内核。

open() 是 sys_open 的用户态薄封装,只负责传参和触发系统调用,真正打开文件的是内核里的 sys_open

-------------------------------------------------------------------------------------------------------------

Linux 内核和应用层这一块,可以把它理解成下面这座"三层楼":

对于 应用开发和驱动开发 来说,可以这么理解:

用户程序

库函数(libc)

系统调用

内核函数

驱动函数

硬件

但如果再往下追:

内核函数

驱动函数

寄存器读写

CPU总线

硬件设备

真正最底层的是:

readl();
writel();

或者:

gpio_set_value();

最终变成:

CPU访问寄存器

驱动开发本质上就是在做这件事。

用户程序不能直接调用内核函数,必须通过系统调用进入内核;系统调用只是入口,真正完成工作的仍然是内核中的各种函数和驱动函数。

http://www.jsqmd.com/news/1007953/

相关文章:

  • 无锡GEO优化公司口碑排行,本土服务商实力测评(2026年6月最新) - wxxwlm
  • i.MX23视频DAC与SSP接口实战:从寄存器配置到低功耗设计
  • Windows平台企业级消息防撤回技术深度解析与完全实施手册
  • Jabel vs 其他方案:为什么选择Jabel而非升级Java版本的终极指南
  • [智能体-391]:智能体(Agent)市场、MCP 工具市场
  • DRG Save Editor:三分钟快速上手,告别重复刷矿的存档编辑神器
  • 2026最新:佛山除甲醛公司深度横评:6 家热门机构实力 PK,佛山佰家环保脱颖而出 - 专注室内空气检测治理
  • TikTokDownloader终极指南:高效批量下载抖音TikTok视频的完整解决方案
  • 终极免费暗黑破坏神2存档编辑器:可视化修改完全指南
  • ChatGPT公式粘贴Word乱码?AI导出鸭技巧,三步解决,保留原始格式
  • 年薪百万、需求暴涨42倍:AI 时代最火岗位 FDE 到底是干嘛的?
  • PPT模板平台:六类工具的功能与适用场景说明 - 品牌测评鉴赏家
  • 2026年论文降AIGC攻坚战:2026权威工具测评榜与精准避坑指南
  • T5-Base模型:统一文本转换框架的终极实战指南
  • Python开发中的最佳实践:代码质量与团队协作
  • FunClip终极指南:基于大语言模型的智能视频剪辑解决方案
  • Kinetis SDK HAL驱动:RCM、SCG、SIM模块的时钟与复位管理实战
  • 苏州学历提升哪家靠谱?7大校区直营机构对比,选对少走3年弯路 - 学历提升信息早知道
  • 如何在5分钟内搭建属于自己的本地语音合成系统?
  • 降AIGC黑科技!AI率92%暴降至5%!实测10款降AIGC网站!免费降AIGC额度薅到爽!
  • ATT推出iPad专属“无限日通“蜂窝套餐,每天仅需3美元
  • 3步免费解锁Grammarly高级版:自动化Cookie获取工具实战指南
  • WorkshopDL:终极Steam创意工坊下载器,免费获取跨平台模组资源
  • Mockoon完整指南:5分钟掌握本地API模拟的核心技巧
  • 广州搬家收费全解析:2026年度家庭/企业搬家分项报价明细汇总 - 从来都是英雄出少年
  • 2026云南纯玩团推荐纯玩参考TOP3,纯玩无购物,费用和避坑参考 - 旅游发布
  • 构建可扩展的后端系统:负载均衡与水平扩展策略
  • 光通传奇3 永恒传奇3(GSR版本) (五) 利用CE制作自动打怪挂机简易辅助
  • Citra 3DS模拟器完全指南:在PC上畅玩任天堂3DS游戏的终极方案
  • 广州搬家|搬厂公司盘点 结合资质与项目经验的参考名录 - 互联网科技品牌测评