Parler du mécanisme de fonctionnement du programme de Hello World

小云云
Libérer: 2023-03-17 15:52:01
original
1446 Les gens l'ont consulté

Lorsque nous avons commencé à nous lancer dans la programmation, le premier petit projet que nous avons réalisé était "hello world". En peu de temps, nous avons pu écrire son hello world dans ce langage. Mais ne le regardez pas, ce ne sont que quelques lettres. Cependant, la plupart des gens ne peuvent toujours pas expliquer le mécanisme de fonctionnement interne du programme simple hello world, nous allons donc vous parler aujourd'hui du mécanisme de fonctionnement du programme.

Bonjour tout le monde Comment ces messages sont-ils affichés sur le moniteur ? Le code exécuté par le CPU est définitivement différent du code que nous écrivons dans le programme. À quoi ressemble-t-il ? Comment cela change-t-il du code que nous avons écrit au code que le CPU peut exécuter ? Où est le code lorsque le programme est en cours d'exécution ? Comment sont-ils organisés ? Où sont stockées les variables du programme ? Comment apparaissent les appels de fonction ? Cet article expliquera brièvement le fonctionnement du programme.

Le processus caché de la plateforme de développement

Chaque langage a sa propre plateforme de développement, et la plupart de nos programmes sont nés ici. Le processus de conversion du code source du programme en fichier exécutable est en fait divisé en plusieurs étapes et est très compliqué. Cependant, la plate-forme de développement actuelle prend toutes ces choses par elle-même, ce qui nous apporte non seulement de la commodité, mais cache également de nombreuses implémentations. détails. Par conséquent, la plupart des programmeurs sont uniquement responsables de l'écriture du code, et d'autres travaux de conversion complexes sont effectués en silence par la plate-forme de développement.

D'après ma compréhension, en termes simples, le processus allant du code source au fichier exécutable peut être divisé en les étapes suivantes :

1. Du code source au langage machine et le langage machine résultant est. organisé selon certaines règles. Appelons-le fichier A pour l'instant.

2. Liez le fichier A avec le fichier B (tel qu'une fonction de bibliothèque) requis pour exécuter A pour former le fichier A+

3. Chargez le fichier A+ en mémoire et exécutez le fichier

. (En fait, si vous lisez des ouvrages de référence ou d'autres informations, il peut y avoir plus que ces étapes, mais pour simplifier, je le résume en 3 étapes)

Ce sont les étapes clés pour former un fichier exécutable, et aucun d'entre eux ne peut manquer. Vous voyez maintenant que vous êtes « aveuglé » par la plateforme de développement. Les sections suivantes dissiperont le brouillard et vous donneront le vrai visage de votre plateforme de développement.

Fichier objet

Il existe un dicton classique dans le domaine informatique :

« Tout problème en informatique peut être résolu par une autre couche d'indirection »

"Tout problème dans le domaine de l'informatique peut être résolu en ajoutant une couche intermédiaire"

Par exemple, pour convertir de A en B, vous pouvez d'abord convertir A en fichier A+, puis convertir le fichier A+ en nous avons requis le document B. (En fait, cette méthode est également décrite dans "Comment l'aimer" de Polya. Lors de la résolution de problèmes, vous pouvez simplifier le problème en ajoutant une couche intermédiaire)

Donc du code source au fichier exécutable Le processus peut être compris de cette façon. Il en va de même pour passer du code source aux fichiers exécutables, en ajoutant (constamment) des couches intermédiaires entre eux pour résoudre le problème.

Comme mentionné ci-dessus, convertissez d'abord le programme source en fichier intermédiaire A, puis convertissez le fichier intermédiaire en fichier cible dont nous avons besoin.

C'est la voie à suivre lors du traitement des fichiers.

En fait, le terme plus professionnel pour le fichier A mentionné ci-dessus est : fichier cible. Ce n'est pas un programme exécutable et doit être lié et chargé avec d'autres fichiers cibles avant de pouvoir être exécuté. Pour un programme source, la première chose que la plateforme de développement doit faire est de traduire le programme source en langage machine. Une partie très importante est la compilation. Je pense que beaucoup de gens savent qu'il s'agit de traduire le code source en langage machine (en fait un tas de codes binaires). La connaissance de la compilation est très importante, mais ce n'est pas l'objet de cet article. Si vous êtes intéressé, vous pouvez la rechercher vous-même.

Format du fichier cible :

Voyons maintenant comment le fichier cible mentionné ci-dessus est organisé (c'est-à-dire la structure de stockage).

Origine :

Imaginez comment vous organiseriez ces codes binaires si c'était vous qui les conceviez ? Tout comme les éléments sur le bureau doivent être classés et placés avec soin, afin de faciliter la gestion, les codes binaires traduits sont également stockés dans des catégories, et ceux représentant le code sont placés ensemble, et ceux représentant les données sont placés ensemble. De cette manière, le code binaire est divisé en différents blocs pour le stockage. Une telle zone est appelée un segment.

Normes :

Comme beaucoup de choses en informatique, afin de faciliter la communication entre les gens, la compatibilité des programmes et d'autres problèmes. Un standard a également été développé pour cette méthode de stockage binaire, c'est ainsi que COFF (common object file format) est né. Le format de fichier cible sous les systèmes d'exploitation courants actuels tels que Windows et Linux est similaire à COFF et peut être considéré comme une variante de celui-ci.

a.out :

a.out est le nom par défaut du fichier cible. Autrement dit, lors de la compilation d'un fichier, si le fichier cible compilé n'est pas renommé, un fichier nommé a.out sera généré après compilation.

Je n’entrerai pas dans les raisons spécifiques pour lesquelles ce nom est utilisé ici. Si vous êtes intéressé, vous pouvez le rechercher vous-même sur Google.

L'image suivante peut vous donner une compréhension plus intuitive du fichier cible :

Parler du mécanisme de fonctionnement du programme de Hello World


L'image ci-dessus est une fichier cible typique La structure et la situation réelle peuvent être différentes, mais elles sont toutes dérivées de cette base.

En-tête du fichier ELF : le premier segment de l'image ci-dessus. L'en-tête est l'en-tête du fichier cible, qui contient des informations de base sur le fichier cible. Tels que la version du fichier, le modèle de machine cible, l'adresse d'entrée du programme, etc.

Segment de texte : les données à l'intérieur sont principalement la partie code du programme.

Segment de données : la partie données du programme, telle que les variables.

Segment de relocalisation :

Le segment de relocalisation comprend la relocalisation de texte et la relocalisation de données, qui contiennent des informations de relocalisation. De manière générale, il y aura des références à des fonctions ou variables externes dans le code. Puisqu'il s'agit d'une référence, ces fonctions et variables n'existent pas dans le fichier cible. Lors de leur utilisation, leur adresse réelle doit être indiquée (ce processus se produit lors de la liaison). Ce sont ces tables de relocalisation qui fournissent les informations permettant de trouver ces adresses réelles. Après avoir compris ce qui précède, la relocalisation de texte et la relocalisation de données ne sont pas difficiles à comprendre.

Table des symboles : la table des symboles contient toutes les informations sur les symboles dans le code source. Incluez chaque nom de variable, nom de fonction, etc. Les informations de chaque symbole y sont enregistrées. Par exemple, s'il y a le symbole « étudiant » dans le code, les informations correspondantes de ce symbole sont incluses dans la table des symboles. Y compris le segment où se trouve ce symbole, ses attributs (autorisations de lecture et d'écriture) et d'autres informations associées.

En fait, on peut dire que la source originale de la table des symboles se trouve au stade de l'analyse lexicale de la compilation. Lors de l'analyse lexicale, chaque symbole et ses attributs dans le code sont enregistrés dans la table des symboles.

Table de chaînes : elle a des fonctions similaires à la table de symboles et stocke certaines informations de chaîne.

Une autre chose à dire est que les fichiers cibles sont tous stockés en binaire, et qu'ils sont eux-mêmes des fichiers binaires.

Le fichier cible en réalité sera plus compliqué que ce modèle, mais l'idée est la même, c'est-à-dire qu'il est stocké en fonction du type, plus quelques sections décrivant les informations du fichier cible et les informations nécessaires dans le lien.

segmentation a.out

Hello World

Rien à prouver, étudions maintenant le fichier objet formé après la compilation de hello world, qui est décrit ici en C.

Code source simple hello world :

Parler du mécanisme de fonctionnement du programme de Hello World


Afin d'avoir des données à mettre dans le segment de données, " int a=5”.

S'il est sur VC, cliquez sur Exécuter pour voir le résultat.

Afin de voir clairement comment il est traité en interne, nous utilisons GCC pour compiler.

Exécuter

gcc hello.c

En regardant notre répertoire, il y a un fichier cible supplémentaire a.out.

Parler du mécanisme de fonctionnement du programme de Hello World


Ce que nous voulons faire maintenant, c'est voir ce qu'il y a dans a.out. Il se peut que des enfants se souviennent d'avoir utilisé du texte vim pour. je le pensais si naïvement à l’époque. Mais quel genre de chose est a.out, comment peut-il être exposé si facilement. Oui, vim ne fonctionne pas. "La plupart des problèmes que nous avons rencontrés ont été rencontrés et résolus par nos prédécesseurs." Oui, il existe un outil très puissant appelé objdump. Grâce à lui, nous pouvons comprendre en profondeur divers détails du fichier cible. Bien sûr, il existe également un fichier très utile appelé readelf, qui sera présenté plus tard.

Ces deux outils sont généralement fournis avec Linux, vous pouvez les rechercher vous-même sur Google

Remarque : le code ici est principalement compilé avec GCC sous Linux, et les fichiers cibles sont visualisés à l'aide d'Objdump, readelf. Mais je vais mettre tous les résultats en cours dans l'image, donc si vous n'avez jamais été exposé à Linux auparavant, ce n'est pas un problème de lire le contenu suivant. J'utilise Ubuntu et ça fait du bien~

Voici la structure organisationnelle de a.out : (adresse de départ de chaque segment, taille, etc.)

La commande pour afficher la cible le fichier est objdump -h a.out

Parler du mécanisme de fonctionnement du programme de Hello World


est le même que le format du fichier cible décrit ci-dessus. il est stocké dans des catégories. Le fichier cible est divisé en 6 sections.

De gauche à droite, la première colonne (Idx Name) est le nom du segment, la deuxième colonne (Size) est la taille, VMA est l'adresse virtuelle, LMA est l'adresse physique et File off est le décalage dans le fichier. C'est-à-dire la distance de ce paragraphe par rapport à une référence dans le paragraphe (généralement le début du paragraphe). Le dernier Algn est une description des attributs du segment. Ignorez-le pour l'instant

segment "texte" : segment de code.

segment "data" : Il s'agit du segment de données mentionné ci-dessus, qui enregistre les données dans le code source, généralement des données initialisées.

Segment "bss" : C'est également un segment de données, qui stocke les données non initialisées. Parce que ces données n'ont pas encore reçu d'espace, elles sont stockées séparément.

Segment "rodata" : segment de données en lecture seule, les données qui y sont stockées sont en lecture seule.

"cmment" stocke les informations sur la version du compilateur.

Les deux paragraphes restants n'ont aucune signification pratique pour notre discussion et ne seront pas présentés à nouveau. Pensez simplement qu'ils contiennent des informations sur les liens, la compilation et l'installation.

Remarque :

Le format de fichier cible ici ne répertorie que les principales parties de la situation réelle. Certaines situations réelles ne sont pas répertoriées dans le tableau. Si vous utilisez également Linux, vous pouvez utiliser objdump -X pour répertorier le contenu des segments plus détaillés.

Approfondissez a.out

La partie ci-dessus décrit les segments typiques du fichier cible à travers des exemples, principalement les informations sur les segments, telles que la taille et d'autres attributs associés.

Alors, que contiennent exactement ces segments ? Qu'est-ce qui est exactement stocké dans le segment "texte" ? Utilisons notre objdump.

objdump -s a.out Vous pouvez afficher le format hexadécimal du fichier cible via l'option -s.

Affichez les résultats comme suit :

Parler du mécanisme de fonctionnement du programme de Hello World


Comme le montre la figure ci-dessus, la représentation hexadécimale de chaque segment est formulaire répertorié. On peut voir que l'image est divisée en deux colonnes. La colonne de gauche est la représentation hexadécimale et la colonne de droite affiche les informations correspondantes.

Évidemment, il y a "hello world" dans le segment de données en lecture seule "rodata". . Soupir, il semble que "bonjour" dans le programme soit mal tapé et qu'un "w" supplémentaire soit ajouté à la fin. Il est difficile de prendre des captures d'écran. Pardonne-moi.

Vous pouvez également vérifier la valeur ASCII de "hellow world", et la valeur hexadécimale correspondante est le contenu à l'intérieur.

"commentaire" Le paragraphe mentionné ci-dessus contient des informations sur la version du compilateur. Le contenu après ce paragraphe est : Compilateur GCC, suivi du numéro de version.

Désassemblage a.out

Le processus de compilation convertit toujours d'abord le texte source en forme d'assemblage, puis le traduit en langage machine. (Ajouter une couche intermédiaire) Après avoir vu autant de a.out, il est nécessaire d'étudier sa forme d'assemblage

objdump -d a.out peut lister la forme d'assemblage du fichier. Cependant, seule la partie principale est répertoriée ici, c'est-à-dire la partie fonction principale. En fait, il y a encore beaucoup de travail à faire au début de l'exécution de la fonction principale et après l'exécution de la fonction principale.

signifie initialiser l'environnement d'exécution de la fonction et libérer l'espace occupé par la fonction, etc.

Parler du mécanisme de fonctionnement du programme de Hello World


Dans l'image ci-dessus, le côté gauche est la forme hexadécimale du code et le côté gauche est le formulaire d'assemblage. Les enfants habitués à l’assemblage devraient être capables d’en comprendre la majeure partie, je n’entrerai donc pas dans les détails ici.

Fichier d'en-tête a.out

Lors de l'introduction du format de fichier cible, le concept de fichier d'en-tête a été mentionné, qui contient des informations de base sur le fichier cible. Tels que la version du fichier, le modèle de machine cible, l'adresse d'entrée du programme, etc.

L'image suivante est le format de l'en-tête du fichier :

Vous pouvez utiliser readelf -h pour l'afficher. (Ce qui est affiché dans l'image ci-dessous est hello.o, qui est un fichier compilé mais non lié par le fichier source hello.c. C'est essentiellement la même chose que l'affichage de a.out)

Parler du mécanisme de fonctionnement du programme de Hello World


L'image est divisée en deux colonnes. La colonne de gauche représente les attributs et la colonne de droite représente les valeurs des attributs. La première rangée est souvent appelée le nombre magique. Ce qui suit est une série de chiffres. Je n’entrerai pas dans les détails de leur signification spécifique. Vous pouvez les rechercher vous-même.

Ce qui suit sont quelques informations relatives au fichier cible. Puisqu’il n’est pas étroitement lié à la question dont nous souhaitons discuter, nous n’en discuterons pas ici.

Le contenu ci-dessus utilise des exemples spécifiques pour décrire la forme d'organisation interne du fichier cible. Le fichier cible n'est qu'un processus intermédiaire dans le processus de génération d'un fichier exécutable. Le fichier cible est comment le convertir en fichier exécutable et comment le fichier exécutable est exécuté sera discuté dans les sections suivantes

Une compréhension simple des liens

En termes simples, un lien consiste à combiner plusieurs fichiers exécutables.

Si le programme A fait référence à une fonction définie dans le fichier B, pour que la fonction dans A s'exécute normalement, la partie fonction dans B doit être placée dans le code source de A, alors A et B Le processus de fusionner en un seul fichier est un lien.

Il existe un processus spécial pour relier les programmes, appelé éditeur de liens. Il traite certains fichiers cibles d'entrée et les synthétise dans un fichier de sortie. Ces fichiers cibles ont souvent des références mutuelles de données et de fonctions.

Ci-dessus, nous avons vu le formulaire de désassemblage de hello world, qui est un fichier qui n'a pas été lié, ce qui signifie que lors du référencement d'une fonction externe, son adresse n'est pas connue :

Comme indiqué ci-dessous :

Parler du mécanisme de fonctionnement du programme de Hello World


Dans l'image ci-dessus, l'instruction cal appelle la fonction printf(), car la fonction printf() n'est pas présente à l'heure actuelle, dans ce fichier, son adresse ne peut pas être déterminée. En hexadécimal, "ff ff ff" est utilisé pour représenter son adresse. Après le lien, cette adresse deviendra l'adresse réelle de la fonction, car la fonction a été chargée dans le fichier après le lien.

Classification des liens : les liens peuvent être divisés en liens statiques et liens dynamiques selon l'ordre dans lequel les données ou fonctions liées à A sont fusionnées en un seul fichier.

Lien statique :

Terminez le travail de liaison avant que le programme ne soit exécuté. Autrement dit, le fichier ne peut pas être exécuté tant que le lien n'est pas terminé. Mais cela présente un inconvénient évident, comme les fonctions de bibliothèque. Si le fichier A et le fichier B doivent utiliser une certaine fonction de bibliothèque, une fois le lien terminé, les fichiers liés auront cette fonction de bibliothèque. Lorsque A et B sont exécutés en même temps, il y a deux copies de la fonction bibliothèque dans la mémoire, ce qui gaspille sans aucun doute de l'espace de stockage. Ce gaspillage devient particulièrement évident lorsque le tartre augmente. Les liens statiques présentent également l’inconvénient d’être difficiles à mettre à niveau. Afin de résoudre ces problèmes, de nombreux programmes utilisent aujourd’hui des liens dynamiques.

Lien dynamique : Contrairement au lien statique, le lien dynamique est lié lors de l'exécution du programme. C'est à ce moment-là que le programme est chargé et exécuté. Toujours dans l'exemple ci-dessus, si A et B utilisent tous deux la fonction de bibliothèque Fun(), une seule copie de Fun() doit être en mémoire lorsque A et B sont exécutés.

Il existe de nombreuses connaissances sur les liens, qui seront abordées dans un article dédié dans le futur. Je n’entrerai pas dans les détails ici.

Une explication simple du chargement

Nous savons que pour qu'un programme s'exécute, il doit être chargé en mémoire. Dans le passé, les machines chargeaient l'intégralité du programme dans la mémoire physique. De nos jours, on utilise généralement des mécanismes de stockage virtuel, c'est-à-dire que chaque processus dispose d'un espace d'adressage complet, donnant l'impression que chaque processus peut l'utiliser. Un gestionnaire de mémoire mappe ensuite les adresses virtuelles aux adresses de mémoire physique réelles.

Selon la description ci-dessus, l'adresse du programme peut être divisée en adresse virtuelle et adresse réelle. L'adresse virtuelle est son adresse dans son espace mémoire virtuel et l'adresse physique est l'adresse réelle où elle est chargée.

Parler du mécanisme de fonctionnement du programme de Hello World


Peut-être avez-vous remarqué en visualisant les segments ci-dessus que puisque le fichier n'est pas lié ou chargé, chacun L'adresse virtuelle et l'adresse physique du segment sont tous deux 0. Le processus de chargement de

peut être compris comme suit : attribuez d'abord des adresses virtuelles à chaque partie du programme, puis établissez un mappage de l'adresse virtuelle à l'adresse physique. En fait, l’élément clé est le processus de mappage de l’adresse virtuelle à l’adresse physique. Une fois le programme installé, le compteur de programme PC de la CPU pointe vers la position de départ du code dans le fichier, puis le programme est exécuté en séquence.

Le but de la rédaction de cet article est de démêler le mécanisme de fonctionnement du programme et ce qui se cache derrière l'exécution d'un fichier exécutable. Du code source au fichier exécutable passe généralement par de nombreuses étapes intermédiaires, chaque étape intermédiaire génère un fichier intermédiaire. C'est juste que l'environnement de développement intégré actuel a caché ces étapes. Nous, habitués à l'environnement de développement intégré, avons progressivement ignoré ces importants initiés techniques. Cet article ne présente que l’essentiel de ce processus. Chacun des détails peut être discuté dans un article.

Je pense qu'après avoir lu cet article, tout le monde ne pensera pas que "hello world" n'est qu'une simple petite expérience. J'espère aussi qu'à travers cet article, tout le monde comprendra quel est le mécanisme de fonctionnement du programme et de quoi il s'agit. c'est comment ça marche.

Recommandations associées :

Le mécanisme de fonctionnement sous-jacent et les principes de PHP

Exploration du mécanisme de fonctionnement des fonctions du didacticiel PHP_PHP

Analyse d'un exemple de code du mécanisme d'exécution JavaScript

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!