linux内核源码 最新的linux外核源码分析方法
Linux核心代码的巨大使许多人“望而生畏”,正因为如此,人们对Linux的理解才处于一般水平如果你想透析Linux,深入操作系统的本质,阅读核源代码是最有效的方法众所周知,要成为一名优秀的程序员,需要大量的实践和编写代码。
编程很重要,但是只编程的人很容易把自己局限在自己的知识领域如果我们想扩大我们的知识,我们需要联系其他人编写的代码,特别是那些比我们更高水平的人编写的代码通过这种方式,我们可以跳出自己知识圈的束缚,进入别人的知识圈,了解更多我们通常在短时间内无法理解的信息。
Linux的核心是由无数开源社区的“大神”精心维护的,这些人可以称之为代码大师通过阅读Linux核心代码,我们学到的不仅仅是核心相关知识,更有价值的是学习和体验他们的编程技能和对计算机的理解
我还通过一个项目联系了Linux内核源代码的分析我从源代码的分析中受益匪浅除了获得相关的内核知识外,它还改变了我对内核代码的过去理解:1.核源代码的分析并非“高不可攀”核源代码分析的难度不在于源代码本身,而在于如何使用更合适的分析代码的方法和手段。
内核的巨大使我们无法像分析一般的demo程序那样从主函数一步一步地分析我们需要一种从中间干预的手段来“打破”内核源代码这种“按需索取”的方式使我们能够把握源代码的主线,而不是过度纠结于具体细节2.内核的设计很漂亮。
内核的特殊性决定了内核的执行效率必须足够高,才能满足当前计算机应用的实时要求因此,Linux内核采用C语言和汇编的混合编程但我们都知道,软件执行效率和软件可维护性在很多情况下都是相反的如何在保证内核高效的前提下提高内核的可维护性,取决于内核中的“美”设计。
3.神奇的编程技巧在一般应用软件设计领域,编码的地位可能不会被过度重视,因为开发者更注重软件的良好设计,而编码只是一个实现手段的问题——就像用斧头劈柴一样,不需要太多思考然而,这并不是在核心中建立起来的。
良好的编码设计不仅提高了可维护性,而且提高了代码性能每个人对核心的理解都会有所不同随着我们对核心理解的加深,我们将对其设计和实现的思想有更多的思考和经验因此,本文希望引导更多在Linux内核大门外徘徊的人进入Linux的世界,亲身体验内核的魔力和伟大。
我不是核源代码专家,这样做只是想分享我自己的经验和经验分析源代码,为那些需要提供参考和帮助,说“宏伟”,也是计算机行业,特别是在操作系统核心贡献自己的微薄力量闲话少叙(已经罗嗦了很多,尴尬~),下面我就来分享一下我的Linix核源码分析方法。
二、内核源码难吗?本质上分析Linux内核代码和看别人的代码没什么区别,因为你面前的代码一般不是你自己写的让我们举一个简单的例子,一个陌生人给你一个程序,让你解释程序的功能设计,我认为很多人觉得编程能力必须认为这没什么,只要我耐心地从头到尾阅读他的代码,肯定会找到答案,事实是真的。
所以现在换个假设,如果这个人是Linus,给你的是Linux内核的模块代码,你还会觉得这么容易吗?许多人可能会犹豫也是陌生人(如果Linus认识你,当然不算,呵呵~)给你的代码,为什么给我们的感觉很不一样?我认为有以下原因:。
1.在“外界”看来,Linux内核代码有些神秘,而且很大,突然摆在面前可能会觉得无法下手例如,它可能来自一个非常小的原因——找不到main函数对于简单的demo程序,我们可以从头到尾分析代码的含义,但是核心代码的分析完全失败了,因为没有人能从头到尾看到Linux代码(因为真的没必要,用的时候可以看)。
2.许多人也接触过大型软件的代码,但大多数都是应用程序项目,代码的形式和意义与他们经常接触的业务逻辑有关与核心代码不同,其处理的大多数信息与计算机底部密切相关例如,缺乏操作系统、编译器、汇编、系统结构等相关知识也会使核心代码的阅读出现许多障碍。
3.分析核心代码的方法是不合理的面对大量复杂的核心代码,如果不从全局的角度出发,很容易陷入代码细节的泥潭虽然核心代码很大,但它也有它的设计原则和结构,否则维护它对任何人来说都是一场噩梦!如果我们澄清代码模块的整体设计理念,然后分析代码的实现,分析源代码可能是一件容易和快乐的事情。
我个人就是这样理解这些问题的如果您没有接触过大型软件项目,分析Linux核心代码可能是积累大型项目经验的好机会(事实上,Linux代码是我目前接触到的最大的项目!)假如你对计算机底层了解不够透彻,那么我们可以选择边分析边学习的方式来积累底层知识。
代码分析的进展可能会稍微慢一些,但随着知识的不断积累,我们对Linux核心的“业务逻辑”会逐渐清晰起来最后,如何从全局的角度把握分析的源代码,也是我想和大家分享的经验三、内核源码分析方法第一步:数据收集
从人们理解新事物的角度来看,在探索事物的本质之前,我们必须有一个理解新事物的过程,这个过程是我们对新事物有一个初步的概念例如,如果我们想学习钢琴,我们需要首先了解弹钢琴需要学习基本的音乐理论、简单的乐谱、五行乐谱和其他基本知识,然后学习弹钢琴的技能和指导,最后真正开始练习钢琴。
内核代码的分析也是如此首先,我们需要定位要分析的代码所涉及的内容是进程同步和调度的代码,是内存管理的代码,是设备管理的代码,还是系统启动的代码等巨大的核心决定了我们不能一次分析所有的核心代码,所以我们需要给自己一个合理的分工。
算法设计告诉我们,要解决一个大问题,首先要解决它所涉及的子问题为了定位要分析的代码范围,我们可以使用手头的所有资源,尽可能全面地了解代码的整体结构和一般功能这里提到的所有资源都是指Baidu、谷歌大型网络搜索引擎,或操作系统原理教科书和专业书籍,或他人提供的经验和信息,甚至Linux源代码提供的文档、注释和源代码识别符的名称(不要低估代码中识别符的名称,有时他们可以提供关键信息)。
总之,这里所有的资源都是指你能想到的所有可用资源当然,我们不太可能通过这种形式的信息收集获得我们想要的所有信息我们只想尽可能全面因为信息收集越全面,分析代码过程中可以使用的信息就越多,分析过程的难度就越小。
假设我们想分析Linux变频机制实现的代码,这里有一个简单的例子到目前为止,我们只知道这个排名通过字面意思,我们可以大致猜测它应该与CPU的频率调整有关通过信息收集,我们应该能够获得以下相关信息:1.CPUFreq机制。
2.performance、powersave、userspace、ondemand、conservative调频策略3./driver/cpufreq/4./documention/cpufreq5.P state和C state。
……如果Linux内核代码的分析能够收集到这些信息,应该说是非常“幸运”的毕竟关于Linux内核的信息确实不如.NET和JQuery如此丰富,但与十多年前相比,没有强大的搜索引擎和相关研究数据的时期应该被称为“大丰收”时代!我们甚至通过简单的“搜索”找到了这部分代码所在的源代码文件目录(可能需要一两天)。
不得不说,这样的信息简直就是“价值连城”!第二步:源码定位从数据收集中,我们“幸运”找到了源代码相关的源代码目录但这并不意味着我们确实分析了这个目录下的源代码有时候我们发现的目录可能是分散的,有时候我们发现的目录下有很多与特定机器相关的代码,我们更关心的是待分析代码的主要机制,而不是与机器相关的特定代码(这对我们理解核心的本质更有帮助)。
因此,我们需要仔细选择数据中涉及代码文件的数据当然,这一步不太可能一次完成没有人能保证一次可以选择所有需要分析的源代码文件,而且没有遗漏但我们不必担心,只要我们能掌握与大多数模块相关的核心源文件,通过后期对代码的具体分析,我们自然会找到它们。
回到上面的例子,我们仔细阅读/documention/cpufreq下的文档说明目前,Linux源代码将在源代码目录的documention文件夹中保存与模块相关的文档描述如果待分析的模块没有文档描述,这将增加定位关键源代码文件的难度,但不会导致我们找不到我们想要分析的源代码。
通过阅读文档描述,我们至少可以关注/driver/cpufreq/cpufreq.c这个源文件通过这个对源文件的文档描述,结合之前搜索到的调频策略,很容易关注cpufreq_performance.c、cpufreq_powersave.c、cpufreq_userspace.c、cpufreq_ondemand、cpufreq_conservative.c这五个源文件。
所有涉及的文件都找完了吗?别担心,从他们开始分析,迟早会找到其他源文件如果在windows下使用sourceinsight阅读核心源代码,我们可以通过调用函数和搜索符号引用等功能,结合代码分析,轻松找到其他文件freq_table.c、cpufreq_stats.c和/include/linux/cpufreq.h。
根据搜索到的信息流方向,我们可以完全定位需要分析的源代码文件源代码定位的步骤并不是很关键,因为我们不需要找到所有的源代码文件,我们可以将部分工作推迟到代码分析过程中源代码定位也更为关键,找到部分源代码文件是分析源代码的基础。
第三步:简单注释在定位的源代码文件中,分析每个变量、宏、函数、结构体等代码元素的一般含义和功能之所以称之为简单注释,并不是说这部分的注释工作很简单,而是说这部分的注释只要大致描述相关代码元素的含义,就不能过分细化。
相反,这里的工作实际上是整个分析过程中最困难的一步因为这是第一次深入内核代码,特别是对于第一次分析内核源代码的人,大量不熟悉的GNUC语法和压倒性的宏定义将非常绝望此时只要沉下心来,找出每一个关键难点,就能保证以后遇到类似的难点不会再被困住。
此外,其他与核心相关的知识将继续像树一样扩展例如,cpufreq.C文件开始时会出现“DEFINE_PER_CPU“宏的使用,我们基本上可以通过查阅资料来理解宏的含义和功能这里使用的方法与以前收集数据的方法基本相同。
此外,我们还可以使用sourceinsight提供的功能查看其定义,例如转移到定义,或使用LKML(Linux Kernel Mail List)查阅,真的不可能我们也可以去wwwww.stackoverflow.com问题寻求答案(想知道LKML和stackoverflow是什么?收集数据!收集资料吧!)。
总之,通过使用所有可能的手段,我们总能得到这个宏的含义——为每个CPU定义一个独立使用的变量我们不应该强迫注释描述非常准确(我们甚至不需要找出每个函数的具体实现过程,只要一般功能意义),我们结合收集数据和后代码分析不断改进注释的意义(原始注释和标识符命名在这里非常有用)。
通过不断的注释,不断地查阅数据,不断地修改注释的意义在简单注释了所有涉及的源代码文件后,我们可以达到以下效果:1.源码中代码元素存在的含义基本明确2.找出该模块涉及的基本所有关键源代码文件结合之前收集的信息和数据对待分析代码的整体或架构描述,我们可以比较分析结果和数据,以确定和纠正我们对代码的理解。
这样,通过简单的注释,我们就可以从整体上掌握源代码模块的主要结构这也实现了我
来源:艾瑞卡软件库