Maison > Article > Opération et maintenance > Dans quel fichier est placé le code source du noyau Linux ?
Le code source du noyau Linux est placé dans le répertoire /usr/src/linux. La composition du code source du noyau : 1. Le répertoire arch, qui contient le code du noyau lié à l'architecture matérielle prise en charge par le code source du noyau ; 2. Le répertoire include, qui contient la plupart des fichiers d'inclusion du noyau ; répertoire, qui contient le code de démarrage principal ; 4. répertoire mm, contient tout le code de gestion de la mémoire ; 5. répertoire des pilotes, contient tous les pilotes de périphériques du système ; 6. répertoire Ipc, contient le code de communication inter-processus principal.
L'environnement d'exploitation de ce tutoriel : système linux7.3, ordinateur Dell G3.
Où est le code source du noyau Linux ?
Le code source du noyau Linux peut être obtenu de plusieurs manières. De manière générale, sous le système Linux installé, le contenu du répertoire /usr/src/linux est le code source du noyau.
Pour la lecture du code source, si vous souhaitez procéder plus facilement, il est préférable d'avoir au préalable une certaine compréhension des connaissances de base du code source.
La composition du code source du noyau Linux est la suivante (supposée par rapport au répertoire linux) :
arch
Ce sous-répertoire contient le code principal lié à l'architecture matérielle supportée par ce code source principal . Par exemple, pour la plateforme X86, il s'agit du i386.
include
Ce répertoire contient la plupart des fichiers d'inclusion de base. Il existe également un sous-répertoire pour chaque architecture prise en charge.
init
Ce répertoire contient le code de démarrage principal.
mm
Ce répertoire contient tout le code de gestion de la mémoire. Le code de gestion de la mémoire lié à l'architecture matérielle spécifique se trouve dans le répertoire arch/*/mm. Par exemple, celui correspondant à X86 est arch/i386/mm/fault.c.
drivers
Tous les pilotes de périphériques du système se trouvent dans ce répertoire. Il est ensuite divisé en plusieurs types de pilotes de périphériques, chacun d'entre eux possédant également un sous-répertoire correspondant, tel que le pilote de carte son correspondant à drivers/sound.
Ipc
Ce répertoire contient le code de communication inter-processus de base.
modules
Ce répertoire contient des modules qui ont été construits et peuvent être chargés dynamiquement.
fs Linux
codes de système de fichiers pris en charge. Différents systèmes de fichiers ont différents sous-répertoires correspondant les uns aux autres. Par exemple, le système de fichiers ext2 correspond au sous-répertoire ext2.
Kernel
Code de base principal. Parallèlement, le code lié à la structure du processeur est placé dans le répertoire arch/*/kernel.
Net
Le code de pièce du réseau central. Chaque sous-répertoire à l'intérieur correspond à un aspect du réseau.
Lib
Ce répertoire contient le code de la bibliothèque principale. Le code de la bibliothèque lié à l'architecture du processeur est placé dans le répertoire arch/*/lib/.
Scripts
Ce répertoire contient les fichiers de script utilisés pour configurer le noyau.
Documentation
Ce répertoire contient quelques documents pour référence.
Si vous souhaitez analyser Linux et comprendre l'essence du système d'exploitation, la lecture du code source du noyau est le moyen le plus efficace . Nous savons tous que devenir un bon programmeur nécessite beaucoup de pratique et d’écriture de code. La programmation est importante, mais les personnes qui programment uniquement peuvent facilement se limiter à leurs propres domaines de connaissances. Si nous voulons élargir l’étendue de nos connaissances, nous devons être exposés à davantage de code écrit par d’autres, en particulier à du code écrit par des personnes plus avancées que nous. Grâce à cette approche, nous pouvons sortir des contraintes de notre propre cercle de connaissances, entrer dans le cercle de connaissances des autres et en apprendre davantage sur des informations que nous ne pouvons généralement pas apprendre à court terme. Le noyau Linux est soigneusement entretenu par d'innombrables « maîtres » de la communauté open source, et ces personnes peuvent toutes être qualifiées de meilleurs maîtres du code. En lisant le code du noyau Linux, nous apprenons non seulement des connaissances liées au noyau, mais à mon avis, ce qui est plus précieux, c'est l'apprentissage et la compréhension de leurs compétences en programmation et de leur compréhension des ordinateurs.
Je suis également entré en contact avec l'analyse du code source du noyau Linux à travers un projet dont j'ai beaucoup bénéficié. En plus d'acquérir des connaissances pertinentes sur le noyau, cela a également changé ma compréhension antérieure du code du noyau :
1. L'analyse du code source du noyau n'est pas « hors de portée ». La difficulté de l’analyse du code source du noyau ne réside pas dans le code source lui-même, mais dans la manière d’utiliser des méthodes et des moyens plus appropriés pour analyser le code. L'immensité du noyau nous empêche de l'analyser étape par étape à partir de la fonction principale comme l'analyse d'un programme de démonstration général. Nous avons besoin d'un moyen d'intervention depuis le milieu pour "percer" le code source du noyau un par un. Cette approche « requête à la demande » nous permet de saisir l'essentiel du code source au lieu de trop nous attarder sur des détails précis.
2. Le design du noyau est magnifique. Le statut particulier du noyau détermine que l'efficacité d'exécution du noyau doit être suffisamment élevée pour répondre aux exigences en temps réel des applications informatiques actuelles. Pour cette raison, le noyau Linux utilise une programmation hybride de langage C et d'assembleur. Mais nous savons tous que l’efficacité d’exécution des logiciels et la maintenabilité des logiciels s’opposent dans de nombreux cas. Comment améliorer la maintenabilité du noyau tout en garantissant son efficacité dépend de la « belle » conception du noyau.
3. Compétences en programmation étonnantes. Dans le domaine de la conception générale de logiciels d'application, le statut du codage ne peut pas être surestimé, car les développeurs accordent plus d'attention à la bonne conception des logiciels, et le codage n'est qu'une question de moyens de mise en œuvre, tout comme utiliser une hache pour couper du bois, sans trop de réflexion. Mais cela n’est pas vrai dans le noyau. Une bonne conception de codage améliore non seulement la maintenabilité, mais améliore également les performances du code.
La compréhension du noyau par chacun sera différente. À mesure que notre compréhension du noyau continue de s'approfondir, nous aurons davantage de réflexions et d'expériences sur sa conception et sa mise en œuvre. Par conséquent, cet article espère guider davantage de personnes qui errent hors de la porte du noyau Linux pour entrer dans le monde de Linux et découvrir par elles-mêmes la magie et la grandeur du noyau. Et je ne suis pas un expert en code source du noyau, j'espère juste partager ma propre expérience et mon expérience dans l'analyse du code source et fournir des références et de l'aide à ceux qui en ont besoin. Pour le dire "haut de gamme", cela peut être considéré comme. pour l'industrie informatique, notamment en ce qui concerne le noyau du système d'exploitation, apportez vos propres efforts. Sans plus tarder (c'est déjà trop long, désolé~), permettez-moi de partager ma propre méthode d'analyse du code source du noyau Linux.
Du point de vue des gens qui comprennent de nouvelles choses, avant d'explorer l'essence des choses, il doit y avoir un processus de compréhension de nouvelles choses. Ce processus est ce qui nous fait. comprendre de nouvelles choses Générer un concept préliminaire. Par exemple, si nous voulons apprendre le piano, nous devons d'abord comprendre que jouer du piano nous oblige à apprendre le solfège musical de base, la notation simplifiée, la portée et d'autres connaissances de base, puis à apprendre les techniques de jeu et les doigtés du piano, et enfin nous pouvons réellement commencer. pratiquer le piano.
Il en va de même pour l'analyse du code du noyau. Nous devons d'abord localiser le contenu impliqué dans le code à analyser. Est-ce le code pour la synchronisation et la planification des processus, le code pour la gestion de la mémoire, le code pour la gestion des appareils, le code pour le démarrage du système, etc. La taille énorme du noyau fait que nous ne pouvons pas analyser tout le code du noyau en même temps, nous devons donc nous donner une division raisonnable du travail. Comme nous le dit la conception des algorithmes, pour résoudre un gros problème, nous devons d’abord résoudre les sous-problèmes qu’il implique.
Après avoir localisé la plage de code à analyser, nous pouvons utiliser toutes les ressources disponibles pour comprendre la structure globale et les fonctions générales de cette partie du code de la manière la plus complète possible.
Toutes les ressources mentionnées ici font référence à Baidu, aux moteurs de recherche en ligne à grande échelle de Google, aux manuels de principes du système d'exploitation et aux livres professionnels, ou à l'expérience et aux informations fournies par d'autres, ou même au code source Linux fourni. Documentation, commentaires , et les noms des identifiants du code source (ne sous-estimez pas la dénomination des identifiants dans le code, ils peuvent parfois fournir des informations clés). En bref, toutes les ressources ici font référence à toutes les ressources disponibles auxquelles vous pouvez penser. Bien entendu, il nous est impossible d’obtenir toutes les informations souhaitées grâce à cette forme de collecte d’informations, nous voulons simplement être aussi complets que possible. Parce que plus les informations sont collectées de manière complète, plus d'informations peuvent être utilisées dans le processus ultérieur d'analyse du code et moins le processus d'analyse sera difficile.
Voici un exemple simple, en supposant que l'on souhaite analyser le code implémenté par le mécanisme de conversion de fréquence de Linux. Jusqu'à présent, nous ne connaissons ce terme que par son sens littéral, nous pouvons à peu près deviner qu'il devrait être lié au réglage de la fréquence du CPU. Grâce à la collecte d'informations, nous devrions être en mesure d'obtenir les informations pertinentes suivantes :
1. Mécanisme CPUFreq.
2. performances, économies d'énergie, espace utilisateur, à la demande, stratégies conservatrices de régulation de fréquence.
3. /pilote/cpufreq/.
4. /documentation/cpufreq.
5. État P et état C.
Si vous parvenez à collecter ces informations lors de l'analyse du code du noyau Linux, vous devriez être très "chanceux". Après tout, les informations sur le noyau Linux ne sont en effet pas aussi riches que .NET et JQuery. Cependant, par rapport à il y a plus de dix ans, lorsqu'il n'existait pas de moteurs de recherche puissants ni de documents de recherche pertinents, il devrait être qualifié de « Grand ». L'ère des récoltes ! Grâce à une simple "recherche" (cela peut prendre un ou deux jours), nous avons même trouvé le répertoire du fichier de code source où se trouve cette partie du code. Je dois dire que ce genre d'information est tout simplement "inestimable" !
Dès la collecte de données, nous avons eu la "chance" de trouver le répertoire de code source lié au code source. Mais cela ne signifie pas que nous analysons effectivement le code source de ce répertoire. Parfois, les répertoires que nous trouvons peuvent être dispersés, et parfois les répertoires que nous trouvons contiennent beaucoup de code lié à des machines spécifiques, et nous nous préoccupons davantage du mécanisme principal du code à analyser plutôt que du code spécialisé lié à la machine ( Cela nous aidera à mieux comprendre la nature du noyau). Par conséquent, nous devons sélectionner soigneusement les informations impliquant des fichiers de code dans les informations. Bien entendu, il est peu probable que cette étape soit réalisée en une seule fois, et personne ne peut garantir que tous les fichiers de code source à analyser pourront être sélectionnés en même temps sans en manquer aucun. Mais nous n'avons pas à nous inquiéter tant que nous pouvons capturer les fichiers sources principaux liés à la plupart des modules, nous pouvons naturellement tous les retrouver grâce à une analyse détaillée du code ultérieurement.
Retour à l'exemple ci-dessus, nous lisons attentivement la documentation sous /documention/cpufreq. Le code source Linux actuel enregistrera la documentation relative au module dans le dossier de documentation du répertoire du code source. Si le module à analyser ne dispose pas de documentation, cela augmentera quelque peu la difficulté de localiser les fichiers de code source clés, mais cela augmentera quelque peu la difficulté de localiser les fichiers de code source clés. cela ne nous empêchera pas de les trouver. Le code source que nous voulons analyser. En lisant la documentation, on peut au moins faire attention au fichier source /driver/cpufreq/cpufreq.c. Grâce à cette documentation des fichiers sources, combinée aux stratégies de modulation de fréquence collectées précédemment, nous pouvons facilement prêter attention aux cinq fichiers sources cpufreq_performance.c, cpufreq_powersave.c, cpufreq_userspace.c, cpufreq_ondemand et cpufreq_conservative.c. Tous les documents concernés ont-ils été retrouvés ? Ne vous inquiétez pas, commencez à les analyser et tôt ou tard vous trouverez d'autres fichiers sources. Si vous utilisez sourceinsight pour lire le code source du noyau sous Windows, nous pouvons facilement trouver d'autres fichiers freq_table.c, cpufreq_stats.c et /include/linux/cpufreq grâce à des fonctions telles que l'appel de fonctions et la recherche de références de symboles, combinées à l'analyse de code. h.
Selon le sens du flux d'informations recherché, nous pouvons localiser complètement les fichiers de code source qui doivent être analysés. L'étape de localisation du code source n'est pas très critique, car nous n'avons pas besoin de trouver tous les fichiers du code source et nous pouvons reporter une partie du travail au processus d'analyse du code. Le positionnement du code source est également essentiel. La recherche d'une partie des fichiers de code source constitue la base de l'analyse du code source.
Commentaires simples
Dans les fichiers de code source localisés, analysez la signification générale et la fonction de chaque variable, macro, fonction, structure et autres éléments de code. La raison pour laquelle cela est appelé un commentaire simple ne signifie pas que le travail de commentaire dans cette partie est très simple, mais cela signifie que le commentaire dans cette partie n'a pas besoin d'être trop détaillé, à condition qu'il décrive grossièrement la signification du commentaire. éléments de code pertinents. Au contraire, le travail ici constitue en réalité l’étape la plus difficile de tout le processus d’analyse. Parce que c'est la première fois qu'on approfondit le code du noyau, en particulier pour ceux qui analysent le code source du noyau pour la première fois, le grand nombre de syntaxes GNU C inconnues et les définitions de macros écrasantes seront très décevantes. À ce stade, tant que vous vous calmez et comprenez chaque difficulté clé, vous pouvez vous assurer que vous ne serez pas piégé lorsque vous rencontrerez des difficultés similaires à l'avenir. De plus, nos autres connaissances liées au noyau continueront à s’étendre comme un arbre.
Par exemple, l'utilisation de la macro "DEFINE_PER_CPU" apparaîtra au début du fichier cpufreq.c On peut essentiellement comprendre la signification et la fonction de cette macro en consultant les informations. La méthode utilisée ici est fondamentalement la même que la méthode utilisée pour collecter des données auparavant. De plus, nous pouvons également utiliser la fonction d'accès à la définition fournie par sourceinsight pour afficher sa définition, ou utiliser LKML (Linux Kernel Mail List) pour l'afficher. Bref, en utilisant tous les moyens possibles, nous pouvons toujours comprendre la signification de cette macro : définir une variable utilisée indépendamment pour chaque CPU.
Nous n'insistons pas pour décrire avec précision les commentaires en une seule fois (nous n'avons même pas besoin de comprendre le processus de mise en œuvre spécifique de chaque fonction, il suffit de comprendre la signification fonctionnelle générale), nous combinons les informations collectées et les éléments suivants code L'analyse améliore continuellement la signification des commentaires (les commentaires originaux et la dénomination des identifiants dans le code source sont ici d'une grande utilité). Grâce à une annotation constante, une référence constante à l'information et une modification constante du sens des annotations.
Après avoir simplement annoté tous les fichiers de code source impliqués, nous pouvons obtenir les résultats suivants :
1. Comprenez essentiellement la signification des éléments de code dans le code source.
2. Fondamentalement, tous les fichiers de code source clés impliqués dans ce module ont été trouvés.
Combiné à la description globale ou architecturale du code à analyser sur la base des informations et données précédemment collectées, nous pouvons comparer les résultats de l'analyse avec les données pour déterminer et réviser notre compréhension du code. De cette façon, à travers un simple commentaire, nous pouvons saisir la structure principale du module de code source dans son ensemble. Cela atteint également l’objectif fondamental de notre simple annotation.
Après avoir terminé les commentaires simples du code, on peut considérer que l'analyse du module est à moitié terminée et que le contenu restant est une analyse approfondie et une compréhension approfondie du code. Les commentaires simples ne peuvent pas toujours décrire de manière très précise la signification spécifique des éléments de code, des commentaires détaillés sont donc très nécessaires. Dans cette étape, nous devons clarifier les points suivants :
1. Lorsque la définition de variable est utilisée.
2. Lorsque le code défini par la macro est utilisé.
3. La signification des paramètres de fonction et des valeurs de retour.
4. Le flux d'exécution et la relation d'appel de la fonction.
5. La signification spécifique et les conditions d'utilisation des champs de structure.
Nous pouvons même appeler cette étape une annotation de fonction détaillée, car la signification des éléments de code en dehors de la fonction est fondamentalement claire dans de simples commentaires. Le flux d'exécution et l'algorithme de la fonction elle-même sont les tâches principales de cette partie d'annotation et d'analyse.
Par exemple, comment l'algorithme d'implémentation de la politique cpufreq_ondemand (dans la fonction dbs_check_cpu) est implémenté. Il faut analyser progressivement les variables utilisées par la fonction et les fonctions appelées pour comprendre les tenants et les aboutissants de l'algorithme. Pour de meilleurs résultats, nous avons besoin de l'organigramme d'exécution et du diagramme de relation d'appel de fonction de ces fonctions complexes, qui est le moyen d'expression le plus intuitif.
Grâce aux commentaires de cette étape, nous pouvons fondamentalement comprendre pleinement le mécanisme global de mise en œuvre du code à analyser. Tous les travaux d’analyse peuvent être considérés comme terminés à 80 %. Cette étape est particulièrement critique. Il faut essayer de rendre les informations d'annotation suffisamment précises pour mieux comprendre la division des modules internes du code à analyser. Bien que le noyau Linux utilise la syntaxe de macro "module_init" et "module_exit" pour déclarer les fichiers du module, la division des sous-fonctions au sein du module est basée sur une compréhension complète des fonctions du module. Ce n'est qu'en divisant correctement le module que nous pouvons déterminer les fonctions et variables externes fournies par le module (en utilisant les symboles exportés par EXPORT_SYMBOL_GPL ou EXPORT_SYMBOL). Ce n'est qu'alors que nous pourrons passer à l'étape suivante d'analyse des dépendances des identifiants au sein du module.
En divisant les modules de code dans la quatrième étape, nous pouvons "facilement" analyser les modules un par un. Généralement, on peut partir des fonctions d'entrée et de sortie du module en bas du fichier (les fonctions déclarées par "module_init" et "module_exit" sont généralement en fin de fichier), en fonction des fonctions qu'elles appellent (fonctions définies par nous-mêmes ou d'autres modules) et les fonctions utilisées. Les variables clés (variables globales de ce fichier ou variables externes d'autres modules) dessinent un diagramme de dépendances "fonction-variable-fonction" - nous l'appelons diagramme de dépendance d'identifiant.
Bien sûr, la relation de dépendance des identifiants au sein du module n'est pas une simple structure arborescente, mais dans de nombreux cas, il s'agit d'une relation de réseau complexe. À ce stade, le rôle de nos commentaires détaillés sur le code est reflété. Nous divisons le module en sous-fonctions en fonction de la signification de la fonction elle-même et extrayons l'arbre de dépendance des identifiants de chaque sous-fonction.
Grâce à l'analyse des dépendances des identifiants, vous pouvez clairement montrer quelles fonctions sont appelées par les fonctions définies par le module, quelles variables sont utilisées et les dépendances entre les sous-fonctions du module— — Quelles fonctions et variables sont partagées, etc.
Interdépendance entre les modules
Une fois tous les diagrammes de dépendances des identifiants internes du module triés, il peut être facilement obtenu en fonction des variables ou des fonctions d'autres modules utilisés par les dépendances du module. La relation de dépendance du module de code
cpufreq peut être exprimée comme la relation suivante.
Grâce au diagramme de dépendance entre les modules, l'état et la fonction du module dans l'ensemble du code à analyser peuvent être clairement exprimés. Sur cette base, nous pouvons classer les modules et trier la relation architecturale du code.
Comme le montre le diagramme de dépendance des modules de cpufreq, nous pouvons clairement voir que tous les modules de stratégie de modulation de fréquence dépendent des modules de base cpufreq, cpufreq_stats et freq_table. Si nous faisons abstraction des trois modules dépendants dans le cadre de base du code, ces modules de stratégie de modulation de fréquence sont construits sur ce cadre et sont responsables de l'interaction avec la couche utilisateur. Le module principal cpufreq fournit des pilotes et d'autres interfaces associées chargées d'interagir avec le système sous-jacent. Par conséquent, nous pouvons obtenir le diagramme d’architecture de module suivant.
Bien sûr, le diagramme d'architecture n'est pas un épissage inorganique de modules. Nous devons également enrichir la signification du diagramme d'architecture en fonction des informations que nous consultons. Par conséquent, les détails du diagramme d'architecture ici varieront en fonction de la compréhension de différentes personnes. Mais la signification du corps principal du diagramme d’architecture est fondamentalement la même. À ce stade, nous avons terminé toutes les analyses du code du noyau à analyser.
Recommandations associées : "Tutoriel vidéo Linux"
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!