Heim  >  Artikel  >  System-Tutorial  >  Eingehende Analyse des Linux-Kernel-Quellcodes und Erkundung des Wesens des Betriebssystems

Eingehende Analyse des Linux-Kernel-Quellcodes und Erkundung des Wesens des Betriebssystems

WBOY
WBOYOriginal
2024-08-08 09:33:081040Durchsuche

深入解析 Linux 内核源码,探索操作系统本质

1. Meine Meinung zum Kernel-Quellcode

Die schiere Größe des Linux-Kernel-Codes macht viele Menschen „entmutigt“. Gerade deshalb ist das Verständnis der Menschen von Linux nur auf einem allgemeinen Niveau. Wenn Sie Linux analysieren und in die Natur des Betriebssystems eintauchen möchten, ist das Lesen des Kernel-Quellcodes der effektivste Weg. Wir alle wissen, dass es viel Übung und Codekompilierung erfordert, um ein ausgezeichneter Programmierer zu werden (Analyse des Linux-Kernel-Quellcodes). Programmieren ist immer noch wichtig, und oft können sich Menschen, die nur programmieren, leicht auf ihre eigenen Wissensgebiete beschränken. Wenn wir die Breite unseres Wissens erweitern wollen, müssen wir uns stärker mit Code auskennen, der von anderen geschrieben wurde, insbesondere mit Code, der von Leuten geschrieben wurde, die fortgeschrittener sind als wir. Auf diese Weise können wir aus der Enge unseres eigenen Wissenskreises ausbrechen, in den Wissenskreis anderer eintreten und mehr über Informationen erfahren, die wir normalerweise auf kurze Sicht nur schwer verstehen können. Der Linux-Kernel wird von unzähligen „Meistern“ der Open-Source-Community sorgfältig gepflegt, und diese Leute können als Top-Code-Experten bezeichnet werden. Durch das Lesen des Linux-Kernel-Codes lernen wir nicht nur Kernel-bezogenes Wissen, sondern meiner Meinung nach ist es noch wertvoller, ihre Programmiermethoden und ihr Verständnis für Computer zu erlernen und zu spüren. Durch ein Projekt bin ich auch mit der Analyse des Linux-Kernel-Quellcodes in Berührung gekommen. Ich habe von der Analyse des Quellcodes sehr profitiert. Ich habe nicht nur relevante Kernel-Kenntnisse erworben, sondern auch mein bisheriges Verständnis von Kernel-Code verändert:

1. Die Analyse des Kernel-Quellcodes ist nicht „außer Reichweite“. Die Schwierigkeit der Kernel-Quellcode-Analyse liegt nicht im Quellcode selbst, sondern darin, wie geeignetere Methoden und Methoden zur Analyse des Codes verwendet werden können. Die Komplexität des Kernels bedeutet, dass wir ihn nicht Schritt für Schritt von der Hauptfunktion aus analysieren können, wie wir es bei einem normalen Demoprogramm tun. Wir brauchen eine Möglichkeit, von der Mitte aus einzugreifen, um den Kernel-Quellcode Stück für Stück zu „durchbrechen“. Diese „On-Demand“-Formate ermöglichen es uns, den Hauptstrang des Quellcodes zu erfassen, anstatt uns zu sehr in den spezifischen Details zu verlieren.

2. Das Design des Kerns ist wunderschön. Der besondere Status des Kernels bestimmt, dass die Ausführungseffizienz des Kernels hoch genug sein muss, um den Echtzeitanforderungen aktueller Computeranwendungen gerecht zu werden. Daher verwendet der Linux-Kernel eine Hybridprogrammierung aus C-Sprache und Assembler. Und wir alle wissen, dass die Effizienz der Softwareausführung und die Wartbarkeit der Software in vielen Fällen im Widerspruch zueinander stehen. Wie die Wartbarkeit des Kernels verbessert und gleichzeitig die Effizienz des Kernels sichergestellt werden kann, hängt von diesen „schönen“ Designs im Kernel ab.

3. Erstaunliche Programmiermethode. Im Bereich des allgemeinen Anwendungssoftware-Designs darf der Status der Codierung nicht überbewertet werden, da Entwickler dem guten Design von Software mehr Aufmerksamkeit schenken und Codierung nur eine Frage der Implementierungsmethode ist – genau wie die Verwendung einer Axt zum Hacken von Brennholz, ohne zu viel denken. Und dies ist im Kernel nicht verankert. Ein gutes Codierungsdesign verbessert nicht nur die Wartbarkeit, sondern auch die Codeleistung.

Jeder wird ein anderes Verständnis des Kernels haben, je tiefer sich unser Verständnis des Kernels vertieft, desto mehr Gedanken und Gefühle werden wir über sein Design und seine Implementierung haben. Daher möchte dieser Artikel mehr Menschen, die sich außerhalb des Linux-Kernel-Raums bewegen, dazu anleiten, in die Welt von Linux einzutauchen und die Magie und Großartigkeit des Kernels selbst zu erleben. Und ich bin kein Experte für Kernel-Quellcode. Ich hoffe nur, dass ich meine eigenen Erfahrungen und Erfahrungen bei der Analyse von Quellcode weitergeben und denjenigen, die sie benötigen, Referenz und Hilfe bieten kann Für die Computerindustrie tragen Sie insbesondere im Hinblick auf den Betriebssystemkern Ihre eigenen bescheidenen Anstrengungen bei. Lassen Sie mich ohne weitere Umschweife (es ist schon zu langatmig und peinlich ~) meine eigene Methode zur Analyse des Linux-Kernel-Quellcodes vorstellen.

2. Ist es schwierig, den Kernel-Quellcode zu finden?

Im Wesentlichen unterscheidet sich die Analyse des Linux-Kernel-Codes nicht vom Betrachten des Codes anderer Leute, da der Code vor Ihnen normalerweise nicht der Code ist, den Sie selbst geschrieben haben. Nehmen wir zunächst ein einfaches Beispiel. Ein Fremder gibt Ihnen zufällig ein Programm und bittet Sie, den funktionalen Aufbau des Programms zu erklären, nachdem er den Quellcode gelesen hat. Ich denke, viele Leute, die denken, dass ihre Programmierkenntnisse in Ordnung sind, müssen denken, dass dies nichts ist , solange ich seinen Code geduldig von Anfang bis Ende lese, würde ich definitiv die Antwort finden, aber das ist tatsächlich der Fall. Lassen Sie uns nun die Annahme ändern: Wenn diese Person Linus ist und er Ihnen den Code eines Moduls des Linux-Kernels gibt, denken Sie, dass es immer noch so einfach ist? Viele Menschen zögern vielleicht. Warum denken wir so unterschiedlich über den Code, den Ihnen derselbe Fremde gegeben hat (ganz zu schweigen davon, ob Linus Sie kennt, haha~)? Ich denke, es gibt folgende Gründe:

1. Der Linux-Kernel-Code ist für die „Außenwelt“ etwas mysteriös, aber er ist sehr umfangreich und kann schwierig zu starten sein, wenn er vor Ihnen liegt. Es kann beispielsweise einen sehr kleinen Grund haben – die Hauptfunktion kann nicht gefunden werden. Für ein einfaches Demoprogramm können wir die Bedeutung des Codes von Anfang bis Ende analysieren, und die Methode zur Analyse des Kernelcodes ist völlig wirkungslos, da niemand den Linux-Code von Anfang bis Ende lesen kann (weil dies wirklich nicht erforderlich ist). , und wenn es verwendet wird, schauen Sie es sich einfach an).

2. Viele Menschen sind auch mit dem Code kleiner Software in Berührung gekommen, aber die meisten davon sind Anwendungsprojekte. Die Form und Bedeutung des Codes hängt mit der Geschäftslogik zusammen, mit der sie häufig in Kontakt kommen. Der Kernel-Code ist anders. Die meisten der von ihm verarbeiteten Informationen hängen eng mit der untersten Schicht des Computers zusammen. Beispielsweise erschwert der Mangel an relevanten Kenntnissen über Betriebssysteme, Compiler, Assembly, Architektur usw. auch das Lesen des Kernel-Codes.

3. Die Methode zur Analyse des Kernelcodes ist nicht sinnvoll genug. Angesichts einer großen Menge an komplexem Kernel-Code kann es leicht passieren, dass man im Sumpf der Codedetails stecken bleibt, wenn man nicht aus einer globalen Perspektive mit Linux Mint beginnt. Schließlich ist der Kernel-Code riesig und verfügt auch über Designprinzipien und Architektur. Andernfalls wäre die Wartung für jeden ein Albtraum! Wenn wir die allgemeine Designidee des Codemoduls klären und dann die Implementierung des Codes analysieren, ist die Analyse des Quellcodes möglicherweise einfach und erfreulich.

linux内核源码剖析_linux内核源码是什么语言_linux内核源码分析

Das ist mein persönliches Verständnis dieser Probleme. Wenn Sie noch nie mit kleinen Softwareprojekten in Berührung gekommen sind, kann die Analyse des Linux-Kernel-Codes eine gute Gelegenheit sein, Erfahrungen in kleinen Projekten zu sammeln (in der Tat ist Linux-Code das größte Projekt, mit dem ich bisher in Kontakt gekommen bin!). Wenn Sie die zugrunde liegenden Aspekte von Computern nicht gründlich genug verstehen, können wir uns dafür entscheiden, grundlegendes Wissen durch gleichzeitiges Analysieren und Lernen anzusammeln. Der Fortschritt bei der Analyse des Codes mag zunächst etwas langsam sein, aber mit zunehmender Wissenszunahme wird unser Verständnis der „Geschäftslogik“ des Linux-Kernels nach und nach klarer. Der letzte Punkt ist, wie man den Quellcode der Analyse aus einer globalen Perspektive beherrscht. Dies ist auch die Erfahrung, die ich mit Ihnen teilen möchte.

3. Methode zur Kernel-Quellcode-Analyse

Schritt eins: Datenerfassung

Aus der Perspektive des Menschen, der neue Dinge versteht, muss es einen Prozess des Verstehens neuer Dinge geben, bevor er das Wesentliche der Dinge erforscht. Dieser Prozess ermöglicht es uns, ein vorläufiges Konzept für neue Dinge zu entwickeln. Wenn wir zum Beispiel Gitarre lernen wollen, müssen wir zunächst verstehen, dass das Gitarrespielen das Erlernen grundlegender Blattgesänge, vereinfachter Notation, Notenlinien und anderer Grundkenntnisse erfordert. Anschließend müssen wir die Methoden und Fingersätze des Erhu-Spiels erlernen und schließlich damit beginnen Gitarre üben.

Das Gleiche gilt für die Analyse des Kernel-Codes. Zuerst müssen wir den Inhalt des zu analysierenden Codes lokalisieren. Handelt es sich um den Code für die Prozesssynchronisierung und -planung, den Code für die Videospeicherverwaltung, den Code für die Geräteverwaltung, den Code für den Systemstart usw. Die Komplexität des Kernels bestimmt, dass wir nicht den gesamten Kernel-Code auf einmal analysieren können, daher müssen wir uns eine angemessene Arbeitsteilung geben. Wie uns das Algorithmusdesign sagt, müssen wir zur Lösung eines großen Problems zunächst die damit verbundenen Teilprobleme lösen.

Nachdem wir den zu analysierenden Codebereich lokalisiert haben, können wir alle verfügbaren Ressourcen nutzen, um die Gesamtstruktur und die allgemeinen Funktionen dieses Teils des Codes so umfassend wie möglich zu verstehen.

源码

Alle hier genannten Ressourcen beziehen sich auf Baidu, die kleine Online-Suchmaschine von Google, Lehrbücher und Fachbücher zu Betriebssystemprinzipien oder auf von anderen bereitgestellte Erfahrungen und Informationen oder sogar auf Dokumente, Kommentare und Quellcode, die vom Linux-Quellcode bereitgestellt werden. Der Name der Kennung (Unterschätzen Sie nicht die Benennung von Bezeichnern im Code, manchmal können sie wichtige Informationen liefern.) Tatsächlich beziehen sich alle Ressourcen hier auf alle verfügbaren Ressourcen, die Ihnen einfallen. Tatsächlich ist es unwahrscheinlich, dass wir mit diesen Methoden der Informationssammlung alle gewünschten Informationen erhalten. Wir möchten lediglich so umfassend wie möglich sein. Denn je umfassender die Informationen gesammelt werden, desto mehr Informationen können bei der Analyse des Codes verwendet werden und die Schwierigkeit des Analyseprozesses wird geringer.

Hier ist ein einfaches Gegenbeispiel. Angenommen, wir möchten den Code analysieren, der vom Frequenzkonvertierungsmechanismus von Linux implementiert wird. Bisher kennen wir diesen Begriff nur aus der wörtlichen Bedeutung und können grob darauf schließen, dass er mit der Frequenzanpassung der CPU zusammenhängt. Durch die Informationssammlung sollten wir in der Lage sein, die folgenden relevanten Informationen zu erhalten:

1. CPUFreq-Mechanismus.

2. Leistung, Energiesparen, Userspace, OnDemand, konservative Frequenzregulierungsstrategien.

3. /driver/cpufreq/.

linux内核源码是什么语言_linux内核源码剖析_linux内核源码分析

4. /documention/cpufreq.

5. Pstate und Cstate.

……

Wenn Sie diese Art von Informationen bei der Analyse des Linux-Kernel-Codes sammeln können, kann man sagen, dass Sie großes „Glück“ haben. Obwohl die Informationen über den Linux-Kernel tatsächlich nicht so umfangreich sind wie die von .NET und JQuery, sollte man im Vergleich zu vor mehr als zehn Jahren, als es noch keine leistungsstarken Suchmaschinen und keine relevanten Forschungsmaterialien gab, von einer Ära der „großen Ernte“ sprechen! Durch eine einfache „Suche“ (die ein bis sieben Tage dauern kann) haben wir sogar das Quellcode-Dateiverzeichnis gefunden, in dem sich dieser Teil des Codes befindet. Ich muss sagen, dass diese Art von Informationen einfach „unbezahlbar“ sind!

Schritt 2: Speicherort des Quellcodes

Bei der Datenerfassung hatten wir „Glück“, das Quellcodeverzeichnis zu finden, das sich auf den Quellcode bezieht. Und das bedeutet nicht, dass wir tatsächlich den Quellcode in diesem Verzeichnis analysieren. Manchmal sind die Verzeichnisse, die wir finden, möglicherweise verstreut, und manchmal enthalten die Verzeichnisse, die wir finden, viel Code, der sich auf bestimmte Maschinen bezieht, und wir kümmern uns mehr um den Hauptmechanismus des zu analysierenden Codes als um den speziellen Code, der sich auf die Maschine bezieht ( Dies wird uns helfen, die Natur des Kernels besser zu verstehen. Zu diesem Zweck müssen wir die Informationen, die Codedateien in den Informationen enthalten, sorgfältig auswählen. Tatsächlich ist es unwahrscheinlich, dass dieser Schritt sofort abgeschlossen wird, und niemand kann garantieren, dass alle zu analysierenden Quellcodedateien gleichzeitig ausgewählt werden können und keine davon übersehen wird. Und wir müssen keine Angst haben, solange wir die Kernquelldateien der meisten Module verstehen, können wir sie später natürlich alle durch eine detaillierte Analyse des Codes finden.

Back to the above example, we carefully read the documentation under /documention/cpufreq. The current Linux source code will save module-related documentation in the documentation folder of the source code directory. If the module to be analyzed does not have documentation, this will somewhat reduce the difficulty of locating key source code files and will not cause us to be unable to find them. The source code we want to analyze. By reading the documentation, we can at least pay attention to the source file /driver/cpufreq/cpufreq.c. Through this documentation of the source files, combined with the previously collected frequency modulation strategies, we can easily pay attention to the five source files cpufreq_performance.c, cpufreq_powersave.c, cpufreq_userspace.c, cpufreq_ondemand, and cpufreq_conservative.c. Have all the documents involved been found? Don't be afraid, start analyzing from them, and sooner or later you will find other source files. If you use sourceinsight to read the kernel source code under Windows, we can easily find other files freq_table.c, cpufreq_stats.c and /include/linux/cpufreq through functions such as function calling and searching for symbol references, combined with code analysis. h.

According to the searched information flow direction, we can completely locate the source code files that need to be analyzed. The step of source code locating is not very critical, because we do not need to find all source code files, and we can defer part of the work to the process of analyzing the code. Source code location is also critical. Finding a part of the source code file is the basis for analyzing the source code.

Step 3: Simple comments

In the located source code files, analyze the general meaning and function of each variable, macro, function, structure and other code elements. The reason why this is called a simple comment does not mean that the comment work in this part is very simple, but it means that the comment in this part does not need to be too detailed, as long as it roughly describes the meaning of the relevant code elements. On the contrary, the work here is of course the most difficult step in the entire analysis process. Since this is the first time to go deep into the kernel code, especially for those who are analyzing the kernel source code for the first time, the large number of unfamiliar GNU C sentence patterns and overwhelming macro definitions will be very disappointing. At this time, as long as you calm down and understand each key difficulty, you can ensure that you will not be forced to retreat when encountering similar difficulties in the future. Moreover, our other knowledge related to the kernel will continue to expand like a tree.

For example, the use of the "DEFINE_PER_CPU" macro will appear at the beginning of the cpufreq.c file. We can basically understand the meaning and function of this macro by consulting the information. The method used here is basically the same as the method used to collect data before. In addition, we can also use the transfer definition and other functions provided by sourceinsight to view its definition, or use LKML (LinuxKernelMailList) to check it. If this does not work, we can also ask questions for answers. (Want to know what LKML and stackoverflow are? Collect information!). In fact, with all possible means, we can always get the meaning of this macro - define an independently used variable for each CPU.

linux内核源码剖析_linux内核源码是什么语言_linux内核源码分析

We don’t insist on being able to describe the comments exactly at once (we don’t even need to figure out the specific implementation process of each function, just figure out the general functional meaning), we combine the collected information and the analysis of the above code Continuously establish the meaning of comments (the original comments and identifier naming in the source code are very helpful here). Through constant annotation, constant reference to information, and constant changes in the meaning of annotations.

源码

After we simply annotate all the source code files involved, we can achieve the following effects:

1. Basically understand the meaning of the code elements in the source code.

2. Basically all the key source code files involved in this module were found.

Combined with the overall or structural description of the code to be analyzed based on the previously collected information and data, we can compare the analysis results with the data to determine and revise our understanding of the code. In this way, through a simple comment, we can grasp the main structure of the source code module as a whole. This also achieves the basic purpose of our simple annotation.

Step 4: Detailed notes

After completing the simple comments of the code, you can feel that the analysis of the module is half done, and the remaining content is an in-depth analysis and thorough understanding of the code. Simple comments cannot always describe the specific meaning of code elements very accurately, so detailed comments are very necessary. In this step, we need to clarify the following:

1. When the variable definition is used.

2. When the code defined by the macro is used.

3. The meaning of function parameters and return values.

4. The execution flow and calling relationship of the function.

5. The specific meaning and usage conditions of structure array.

We can even call this step detailed function annotation, because the meaning of code elements outside the function is basically clear in simple comments. The execution flow and algorithm of the function itself are the main tasks of this part of annotation and analysis.

For example, how the implementation algorithm of cpufreq_ondemand policy (in function dbs_check_cpu) is implemented. We need to gradually analyze the variables used by the function and the functions called to understand the ins and outs of the algorithm. For the best results, we need the execution flow chart and function call relationship diagram of this complex function, which is the most intuitive form of expression.

源码

Through the comments in this step, we can basically fully grasp the overall implementation mechanism of the code to be analyzed. And all the analysis work can be felt as 80% completed. This step is particularly critical. We must try to make the annotation information accurate enough so that we can better understand the definition of the internal modules of the code to be analyzed. In fact, the Linux kernel uses the macro sentence patterns "module_init" and "module_exit" to declare module files, and the definition of the internal sub-functions of the module is based on a full understanding of the module's functions. As long as the module is correctly defined, we can figure out what external functions and variables the module provides (using EXPORT_SYMBOL_GPL or symbols imported by EXPORT_SYMBOL). You can proceed to the next step of analyzing the identifier dependencies within the module.

Step 5: Module internal identifier dependencies

By defining the code modules in the fourth step, we can "easily" analyze the modules one by one. Usually, we can start from the module entry and exit functions at the top of the file (the functions declared by "module_init" and "module_exit" are usually at the end of the file) Linux kernel source code analysis, according to the functions they call (self-defined or other The function of the module) and the key variables used (global variables in this file or external variables of other modules) draw a "function-variable-function" dependency diagram - we call it an identifier dependency diagram.

In fact, the identifier dependency relationship within the module is not a simple tree structure, but in many cases is a complex network relationship. At this time, the role of our detailed comments on the code becomes apparent. We define the sub-functions of the module according to the meaning of the function itself, and extract the identifier dependency tree of each sub-function.

源码

Through identifier dependency analysis, it can be clearly shown that the functions defined by the module call these functions, what variables are used, and the dependencies between module sub-functions - what functions and variables are shared, etc.

Step 6: Interdependencies between modules

Once all module internal identifier dependency diagrams are sorted out, the dependencies between modules can be easily obtained based on the variables or functions of other modules used by the module.

linux内核源码是什么语言_linux内核源码剖析_linux内核源码分析

源码

The module dependency relationship of cpufreq code can be expressed as the following relationship.

源码

Step 7: Module Architecture Diagram

Through the dependency diagram between modules, the status and function of the module in the entire code to be analyzed can be clearly expressed. Based on this, we can classify the modules and sort out the architectural relationship of the code.

源码

As shown in the module dependency diagram of cpufreq, we can clearly see that all frequency modulation strategy modules depend on the core modules cpufreq, cpufreq_stats and freq_table. If we visualize the three dependent modules as the core framework of the code, those frequency modulation strategy modules are built on this framework, and they are responsible for interacting with the user layer. The core module cpufreq provides drivers and other related sockets that are responsible for interacting with the underlying system. Therefore, we can get the following module architecture diagram.

源码

In fact, the architecture diagram is not an inorganic splicing of modules. We also need to combine the data we consult to enrich the meaning of the architecture diagram. Therefore, the details of the architecture diagram here will vary according to different people's understanding. And the meaning of the main body of the architecture diagram is basically the same. At this point, we have completed all the analysis work of the kernel code to be analyzed.

4. Summary

As mentioned at the beginning of the article, it is impossible for us to analyze the entire kernel code. Therefore, collecting information from the code to be analyzed and then analyzing the original story of the code according to the above process is an effective way to understand the essence of the kernel. These methods of analyzing kernel code according to specific needs provide the possibility to quickly enter the world of Linux kernel. Through these methods, we continue to analyze other modules of the kernel, and finally comprehensively obtain our own understanding of the Linux kernel, thus achieving our purpose of learning the Linux kernel.

Finally, I recommend two reference books for learning the kernel. One is "The Design and Implementation of the Linux Kernel", which provides readers with a quick and concise introduction to the main functions and implementation of the Linux kernel. But it will not lead readers into the abyss of Linux kernel code. It is a particularly good reference book for understanding the kernel architecture and getting started with Linux kernel code. At the same time, this book will enhance readers' interest in kernel code. The other is "In-depth Understanding of the Linux Kernel". Why should I say more about this book's masterpiece. I just suggest that if you want to learn this book better, it is best to read it in conjunction with the kernel code. Because this book describes the kernel code in great detail, reading it in conjunction with the code can help us better understand the kernel code. At the same time, in the process of analyzing the kernel code, you can also find information with reference value in this book. Finally, I hope you will enter the world of kernel as soon as possible and experience the surprises that Linux brings to us!

Das obige ist der detaillierte Inhalt vonEingehende Analyse des Linux-Kernel-Quellcodes und Erkundung des Wesens des Betriebssystems. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn