哈喽,我是子牙老师。今天咱们聊聊鼎鼎大名的glibc库是如何写出来的
瓦特?你不知道glibc库是什么?你学C语言的第一句代码#include <stdio.h>,这个stdio.h就是glibc库中的。还有你经常用的函数printf、open、read、write…
我会从这几个角度分析:
- 为什么需要glibc库
- glibc库具体做了哪些事情
- Linux内核的系统调用是如何实现的
- 如何给Linux内核新增一个系统调用
- Linux内核系统调用是如何基于CPU指令syscall实现的
- 单步调试Linux内核论证我说的一切
以下,enjoy
为什么需要glibc库
我们编写Java应用是面向Java虚拟机提供的API编程,编写Python程序是面向Python虚拟机提供的API编程,编写Linux服务端程序是面向Linux系统提供的API编程,那编写Linux内核呢?是面向CPU提供的特性编程
那CPU提供了什么特性导致需要glibc库呢?CPU的特权级划分
在CPU的世界中,Linux内核跑在Ring0,即在CPU的最高特权级中运行,这里就是大家经常说的内核态。Linux系统,或者跑在Linux系统之上的应用,都是运行在Ring3,即大家经常说的用户态
CPU特权级很像古代的帝王与臣子,帝王住在皇宫,臣子住在宫外,臣子要想找帝王,需要有令牌才能进入皇城,令牌的本质是提权。在用户态中运行的程序如果想要访问内核,也需要提权
CPU提供了哪些提权的方式给写操作系统内核的人用呢?一、四门:中断门、调用门、任务门、陷进门;二、x86时代的快速调用指令sysenter、sysexit;三、x64时代的快速调用指令syscall、sysret。
如果你想查看不同架构的CPU使用了哪种提权方式进入内核,可以man syscall查看
今天咱们只聊syscall,其他的,如果你感兴趣,可以自己使用AI工具学习。如果你没概念,你又想玩明白,欢迎学习我的课程《手写操作系统》,或者《实战Linux内核》
聪明的你应该已经知道答案了,CPU提供的指令,需要编写汇编代码才能使用,而绝大多数人是不会汇编的,所以glibc库把它封装成C语言代码给你用,类似这样
是不是方便了很多!
这就是glibc库存在的意义!但是glibc库的存在,不是必须存在,只是为了降低编程门槛。如果你了解了这些,你完全可以不用glibc库去编写应用程序
glibc库做了什么
那glibc库具体做了些什么?
两个方面:一、对于常用的函数,glibc库直接封装好了给你用,比如open、read、write;二、对于不常用的,你也不用直接写汇编代码去调用CPU指令syscall了,它给你封装了一个函数syscall
比如write函数,它底层是这样实现的
比如syscall函数,它底层差不多是这样的
那write函数、syscall函数,是如何与Linux内核关联起来的呢?秘密就是函数的参数
看syscall函数的第一个参数:sysno,这个参数就是调用号,在头文件syscall.h中
当CPU执行指令syscall,就会带着调用号进入内核态。在内核中是如何工作的呢?
Linux内核之系统调用
在Linux内核中,有个系统调用表,是个数组结构
你可能已经醒悟过来了,系统调用号就是这个数组的索引,比如syscall_tables[SYS_WRITE]=sys_write
最后由vfs_write调用相关设备对应的write函数完成任务,比如写一个EXT文件系统中的文件
至此,一切谜底揭晓!
CPU指令syscall
这个非常复杂,直接写文字大家是没有概念的。如果你特别想了解,关注公众号【硬核子牙】回复【syscall】领取视频进行学习
单步调试Linux内核
单步调试Linux内核看下效果
诚不欺我!
顺便说下,其实我最开始做课程《手写Linux发行版》,就是满足一部分学员的需求:Linux系统是如何基于Linux内核写出来的。当我写完以后,有了一个自己百分百控制的Linux系统,使用这个Linux系统研究Linux内核,我发现非常非常方便,真的是意外之喜!