0

0

【Linux内核设计思想】二、内核编译及内核开发的特点

絕刀狂花

絕刀狂花

发布时间:2025-07-23 11:52:14

|

460人浏览过

|

来源于php中文网

原创

【Linux内核设计思想】二、内核编译及内核开发的特点
获取内核源码

linux内核官方网站即可下载最新linux源码

我们一般应该下载最新的稳定版本Linux内核源码进行学习。

源码下载后,通过tar命令进行解压即可

代码语言:javascript代码运行次数:0运行复制
tar xvzf linux-X.X.X.tar.gz

解压后源码会存在linux-X.X.X文件夹中。

内核源码一般都安装在 /usr/src/linux 目录下,但我们开发时不要直接对这个源码树进行开发,因为编译C库所用的内核版本就是该源码树。并且一般不要以root身份修改内核,我们应该自己另外建立一个目录,并以root身份在该目录安装新内核,/usr/src/linux 目录应原封不动的继续存在。

一般以补丁的形式发布对代码的修改,并以补丁的形式接收其他人发布的修改。

内核源码树由很多目录组成,其根目录及描述如下

【Linux内核设计思想】二、内核编译及内核开发的特点

在内核源码树根目录下还有一些文件,COPYING文件是内核许可证,CREDITS是开发者列表并包含了一些内核代码细节,MAINTAINERS是维护内核子系统和驱动程序的维护者列表,Makefile是编译内核的基础。

编译内核

内核源码在编译时可以进行配置和定制,我们可以把自己需要的功能和驱动程序编译进内核。可以配置的选项以CONFIG_FEATURE形式表示,比如,对称多处理器(SMP)的配置选项为CONFIG_SMP,如果设置了该选项,则SMP启用,否则SMP不起作用。配置选项可以用来决定那些文件编译进内核,选项有二选一和三选一,yes/no/module。在三选一的情况下多了一个 module 选项,如果选择 module 选项,表示该配置项已被选定,但编译的时候这部分功能的实现代码是以模块(一种可以动态安装的独立代码段)的形式生成,而 yes 选项表示把代码编译进主内核映像,而不是作为一个模块。

配置选项也可以是字符串或者整数,这些选项不用于控制编译过程,而是用于指定内核源码可以访问的值,一般以预处理宏的形式表示,比如我们可以通过配置选项指定静态分配数组的大小。

内核提供了很多工具来简化内核配置过程,最简单最耗时的是命令行工具,该工具会遍历所有选项并让你选择配置选项 yes/no/module

代码语言:javascript代码运行次数:0运行复制
make config

还有其他更方便的图形工具可供使用

代码语言:javascript代码运行次数:0运行复制
make menuconfigmake xconfigmake gconfigmake defconfig #创建默认配置

也可以查看并修改配置文件来修改这些配置选项,这些选项存放在内核源码树目录的 config 文件中。

通过如下命令验证并更新配置

代码语言:javascript代码运行次数:0运行复制
make oldconfig

配置完成后,就可以编译内核了,使用命令

代码语言:javascript代码运行次数:0运行复制
make

在编译时,往往会打印很多信息并刷屏,如果不想看到这些信息,可以执行下面命令来编译

代码语言:javascript代码运行次数:0运行复制
make > /dev/null

编译好内核后,就到了安装步骤。安装内核与操作系统体系结构和启动引导工具(boot loader)相关,按照要求将内核映像拷贝到适当位置。这个过程可能需要把某个模块拷贝到指定目录,并且需要编译相应的配置文件,建立启动项等等。

我们可以通过命令来把编译好的模块安装到正确的主目录 /lib 下

代码语言:javascript代码运行次数:0运行复制
make modules install

这个命令需要 root 权限。

编译时还会在内核代码树的根目录下创建一个 System.map 文件,这是一个符号对照表,用来将内核符号和它们的起始地址一一对应,调试时可以把内存地址翻译成函数名或变量名以便于理解。

内核开发的特点

内核编程时不能访问C库,即没有 libc 库。

在用户空间编程时,我们可以调用C库函数,但是在内核编程时,内核无法链接标准C函数库,实际上其他一些库也无法使用。但是大部分C库函数都已经在内核中实现了,只要包含相应头文件就可以调用,比如字符串操作函数库 lib/string.c,头文件为

在内核编程时,所用的头文件都是源码树的内核头文件,内核源码文件不能包含外部头文件。

在内核中也有一些C库函数并没有实现,比如 printf() 函数,但是内核中实现了一个叫 printk() 的函数。printk() 函数负责把格式化好的字符串拷贝到内核日志缓冲区,syslog 程序通过读取该缓冲区来获取内核信息。并且 printk() 函数允许通过指定一个标志来设置优先级,syslog 程序根据这个优先级标志来决定在什么地方显示这条系统消息。

内核编程时必须使用 GNU C 。

我们知道,Linux 内核是使用C语言编写的,但是,内核代码并不完全符合 ANSI C 标准,它用到了 gcc 提供的许多语言扩展部分。gcc 是多种 GNU 编译器的集合,它包含的C编译器既可以编译内核,也可以编译 Linux 系统上的其它C源代码。总之,内核开发者使用的C语言包含 ISO C99 标准以及 GNU C 扩展特性。下面列举内核源码中使用到的一些C语言扩展:

蓝心千询
蓝心千询

蓝心千询是vivo推出的一个多功能AI智能助手

下载

① 内联函数(inline)

内联函数顾名思义,就是“在字里行间展开”的意思,内联函数会在它被调用的位置展开,这样做消除了函数调用和返回所带来的开销,比如寄存器的存储和恢复等。而且,编译器会把调用函数的代码和函数本身放在一起进行优化,这就有了代码进一步优化的可能。当然内联函数也有缺点,那就是会使代码变长,会占用更多的内存空间和指令缓存。

我们通常把一些对时间要求高,且本身代码长度较短的函数定义为内联函数。那些对时间要求不高且被反复调用的函数不要定义为内联函数。

再定义一个内联函数时,通常需要使用 static 关键字,并且需要使用 inline 进行限定。

代码语言:javascript代码运行次数:0运行复制
static inline func(){    ;}

内联函数必须在使用之前就定义好,否则的话编译器无法进行函数展开。在编程时,通常在头文件中定义内联函数(如果内联函数仅在某个源文件中使用,也可以在该文件头部定义内联函数)。由于使用了 static 关键字,编译时不会为内联函数单独建一个函数体。在内核编程时,考虑到类型安全因素,应优先使用内联函数而不是宏。

② 内联汇编

gcc 编译器支持在C函数中嵌入汇编指令,Linux 内核就是用了C和汇编混合编程,在偏近体系结构的底层或对执行时间要求严格的地方,一般都是使用汇编语言编写的。

③ 分支声明

对于条件选择语句,gcc 内建了一条指令用于优化,如果一个条件经常出现或者很少出现,编译器就可以根据这条指令对条件分支进行优化。在内核中,这条指令被封装成了宏,比如 likely() 和 unlikely()。例如下面一个条件选择语句

代码语言:javascript代码运行次数:0运行复制
if(flag){    ;}

如果 flag 为0的概率远远大于它为真的概率,也就是说 flag 这条分支大概率不会发生,我们可以标记为

代码语言:javascript代码运行次数:0运行复制
/* 我们认为flag大概率为0 */if(unlikely(flag)){    ;}

反之

代码语言:javascript代码运行次数:0运行复制
/* 我们认为flag大概率为1 */if(likely(flag)){    ;}

这种标记大幅提升性能的前提是你的判断是正确的,如果判断错了可能反而会大幅度降低性能。

内核编程时没有像用户空间那样的内存保护机制。

如果是一个用户程序对内存进行非法访问,那么内核会报错,发送 SIGSEGV 并结束进程。但是,如果是内核自身非法访问内存,那么可能它会直接死掉并且不会报错。内核中的内存错误会导致 oops,这也是内核中出现较多的一类错误,并且内核中的内存不会分页,每用掉一个字节,物理内存就减少一个字节。

内核编程时不要轻易使用浮点数。

如果我们在用户空间进行浮点操作,内核会完成从整数操作到浮点操作的转换。但是在内核中使用浮点数会非常麻烦,这需要你人工保存和恢复浮点寄存器,以及其他一些操作都要人工完成,所以在内核编程时不要使用浮点数。

内核只有一个很小且固定的堆栈。

用户空间栈是非常大的,并且可以动态增长,因此我们可以在用户空间编程时分配大量栈内存。但是内核栈的大小是固定的,它和体系结构有关,在 x86 上,栈的大小在编译时配置,可以是4KB或8KB,一般来说,内核栈的大小是两页,在32位机器内核栈大小为8KB,在64位机器内核栈大小为16KB,这是固定的,每个处理器都有自己的栈。

由于内核支持异步中断、抢占和SMP,所以必须时刻注意同步和并发。

内核是很容易产生竞争条件的,内核的许多特性都要求能够并发的访问共享数据,这就要求有同步机制保证不出现竞争条件。

Linux是抢占多任务操作系统,内核的进程调度程序即兴对进程进行调度和重新调度,内核必须对这些任务同步。Linux内核支持多处理器系统,如果没有保护,在多个处理器上运行的代码很可能会同时访问共享的同一资源。中断是异步到来的,不会考虑正在执行的代码,如果不加保护,中断有可能会在代码访问共享资源时到来,而中断处理程序也有可能会访问该共享资源。Linux内核可以抢占,如果不加保护,内核中正在执行的代码可能会被另一段代码抢占,并且这几段代码可能同时访问相同资源。

通常使用自旋锁和信号量来解决竞争问题。

需要考虑可移植性。

Linux是一个可移植的操作系统,也就是说大部分C代码应该与体系结构无关,在各种不同体系结构的计算机上都能编译和执行,这就意味着,必须把体系结构相关的代码从内核代码树的特定目录中分离出来。

相关专题

更多
C语言变量命名
C语言变量命名

c语言变量名规则是:1、变量名以英文字母开头;2、变量名中的字母是区分大小写的;3、变量名不能是关键字;4、变量名中不能包含空格、标点符号和类型说明符。php中文网还提供c语言变量的相关下载、相关课程等内容,供大家免费下载使用。

377

2023.06.20

c语言入门自学零基础
c语言入门自学零基础

C语言是当代人学习及生活中的必备基础知识,应用十分广泛,本专题为大家c语言入门自学零基础的相关文章,以及相关课程,感兴趣的朋友千万不要错过了。

604

2023.07.25

c语言运算符的优先级顺序
c语言运算符的优先级顺序

c语言运算符的优先级顺序是括号运算符 > 一元运算符 > 算术运算符 > 移位运算符 > 关系运算符 > 位运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符。本专题为大家提供c语言运算符相关的各种文章、以及下载和课程。

348

2023.08.02

c语言数据结构
c语言数据结构

数据结构是指将数据按照一定的方式组织和存储的方法。它是计算机科学中的重要概念,用来描述和解决实际问题中的数据组织和处理问题。数据结构可以分为线性结构和非线性结构。线性结构包括数组、链表、堆栈和队列等,而非线性结构包括树和图等。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

255

2023.08.09

c语言random函数用法
c语言random函数用法

c语言random函数用法:1、random.random,随机生成(0,1)之间的浮点数;2、random.randint,随机生成在范围之内的整数,两个参数分别表示上限和下限;3、random.randrange,在指定范围内,按指定基数递增的集合中获得一个随机数;4、random.choice,从序列中随机抽选一个数;5、random.shuffle,随机排序。

580

2023.09.05

c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

516

2023.09.20

c语言get函数的用法
c语言get函数的用法

get函数是一个用于从输入流中获取字符的函数。可以从键盘、文件或其他输入设备中读取字符,并将其存储在指定的变量中。本文介绍了get函数的用法以及一些相关的注意事项。希望这篇文章能够帮助你更好地理解和使用get函数 。

628

2023.09.20

c数组初始化的方法
c数组初始化的方法

c语言数组初始化的方法有直接赋值法、不完全初始化法、省略数组长度法和二维数组初始化法。详细介绍:1、直接赋值法,这种方法可以直接将数组的值进行初始化;2、不完全初始化法,。这种方法可以在一定程度上节省内存空间;3、省略数组长度法,这种方法可以让编译器自动计算数组的长度;4、二维数组初始化法等等。

595

2023.09.22

笔记本电脑卡反应很慢处理方法汇总
笔记本电脑卡反应很慢处理方法汇总

本专题整合了笔记本电脑卡反应慢解决方法,阅读专题下面的文章了解更多详细内容。

1

2025.12.25

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

Rust 教程
Rust 教程

共28课时 | 3.8万人学习

Kotlin 教程
Kotlin 教程

共23课时 | 2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号