Qu’est-ce que C et Assembler comstacknt réellement?

J’ai donc découvert que les programmes C (++) ne compilaient pas réellement en “binary” (j’ai peut-être eu des problèmes ici, dans ce cas, je suis désolé: D) mais à une série de choses (table des symboles , os-related stuff, …) mais …

edit: Je sais que l’assembleur ne “comstack” pas car il ne contient que le jeu d’instructions de votre machine – je n’ai pas trouvé un bon mot pour ce que l’assembleur “assemble”. Si vous en avez un, laissez-le ici comme commentaire et je le changerai.

C comstack généralement en assembleur, simplement parce que cela rend la vie facile au rédacteur mal compilateur.

Le code d’assemblage s’assemble toujours (pas “comstack”) en code object relogeable . Vous pouvez penser à ceci comme code machine binary et données binarys, mais avec beaucoup de décoration et de métadonnées. Les éléments clés sont les suivants:

  • Le code et les données apparaissent dans les “sections” nommées.

  • Les fichiers object déplaçables peuvent inclure des définitions d’ étiquettes , qui font référence à des emplacements dans les sections.

  • Les fichiers object déplaçables peuvent inclure des “trous” à remplir avec les valeurs des étiquettes définies ailleurs. Le nom officiel d’un tel trou est une entrée de réinstallation .

Par exemple, si vous comstackz et assemblez (mais ne liez pas) ce programme

int main () { printf("Hello, world\n"); } 

vous êtes susceptible de finir avec un fichier object relogeable avec

  • Une section de text contenant le code de la machine main

  • Une définition d’étiquette pour main qui pointe au début de la section de texte

  • Une section rodata (données en lecture seule) contenant les octets de la chaîne littérale "Hello, world\n"

  • Une entrée de relocalisation qui dépend de printf et qui pointe vers un “trou” dans une instruction d’appel au milieu d’une section de texte.

Si vous êtes sur un système Unix, un fichier object relogeable est généralement appelé un fichier .o, comme dans hello.o , et vous pouvez explorer les définitions d’étiquettes et les utiliser avec un outil simple appelé nm , et vous pouvez obtenir des informations plus détaillées à partir d’un fichier. outil un peu plus compliqué appelé objdump .

J’enseigne un cours qui couvre ces sujets, et les élèves écrivent un assembleur et un éditeur de liens, ce qui prend quelques semaines, mais quand ils l’ont fait, la plupart d’entre eux ont une très bonne compréhension du code object relogeable. Ce n’est pas une chose si facile.

Prenons un programme en C.

Lorsque vous exécutez «gcc» ou «cl» sur le programme c, il passera par ces étapes:

  1. Lexique préprocesseur (#include, #ifdef, parsing sortinggraphique, traductions d’encodage, gestion des commentaires, macros …)
  2. Analyse lexicale (production de jetons et d’erreurs lexicales).
  3. Analyse syntaxique (production d’un arbre d’parsing et erreurs syntaxiques).
  4. Analyse sémantique (production d’une table de symboles, informations de cadrage et erreurs de cadrage / typage).
  5. Sortie dans l’assemblage (ou un autre format intermédiaire)
  6. Optimisation de l’assemblage (comme ci-dessus). Probablement dans les chaînes ASM encore.
  7. Assemblage de l’assemblage dans un format d’object binary.
  8. Lier l’assemblage à n’importe quelle bibliothèque statique est nécessaire, ainsi que le déplacer si nécessaire.
  9. Sortie de l’exécutable final au format elf ou coff.

En pratique, certaines de ces étapes peuvent être effectuées en même temps, mais il s’agit de l’ordre logique.

Notez qu’il existe un «conteneur» de format elf ou coff autour du binary exécutable réel.

Vous constaterez qu’un livre sur les compilateurs (je recommande le livre Dragon , le livre d’introduction standard sur le terrain) aura toutes les informations dont vous avez besoin et plus encore.

Comme l’a commenté Marco, la liaison et le chargement sont une zone importante et le livre Dragon s’arrête plus ou moins à la sortie du binary exécutable. Passer de là à un système d’exploitation est un processus complexe, que Levine dans Linkers et Loaders couvre.

J’ai wikiwed cette réponse pour permettre aux gens de modifier les erreurs / append des informations.

Il y a différentes phases dans la traduction de C ++ en un exécutable binary. La spécification du langage n’indique pas explicitement les phases de traduction. Cependant, je décrirai les phases de traduction communes.

Source C ++ To Assembly ou Itermediate Language

Certains compilateurs traduisent en fait le code C ++ dans un langage assembleur ou un langage intermédiaire. Ce n’est pas une phase requirejse, mais utile pour le débogage et les optimisations.

Code d’assemblage à object

L’étape suivante consiste à traduire le langage d’assemblage en un code object. Le code object contient un code d’assemblage avec des adresses relatives et des références ouvertes à des sous-routines externes (méthodes ou fonctions). En général, le traducteur met autant d’informations que possible dans un fichier object, tout le rest n’est pas résolu .

Liaison de code (s) d’object

La phase de liaison combine un ou plusieurs codes d’object, résout les références et élimine les sous-programmes en double. La sortie finale est un fichier exécutable . Ce fichier contient des informations sur le système d’exploitation et les adresses relatives .

Exécution de fichiers binarys

Le système d’exploitation charge le fichier exécutable, généralement à partir d’un disque dur, et le place en mémoire. Le système d’exploitation peut convertir les adresses relatives en emplacements physiques. Le système d’exploitation peut également préparer des ressources (telles que des DLL et des widgets d’interface graphique) qui sont requirejses par l’exécutable (ce qui peut être indiqué dans le fichier exécutable).

Compilation directe vers des fichiers binarys Certains compilateurs, tels que ceux utilisés dans les systèmes intégrés, peuvent être compilés directement à partir de C ++ en un code binary exécutable. Ce code aura des adresses physiques au lieu d’une adresse relative et ne nécessitera pas le chargement d’un système d’exploitation.

Avantages

L’un des avantages de ces phases est que les programmes C ++ peuvent être décomposés en pièces, compilés individuellement et liés ultérieurement. Ils peuvent même être liés à des morceaux d’autres développeurs (aussi appelés bibliothèques). Cela permet aux développeurs de comstackr uniquement des éléments en développement et de créer des liens déjà validés. En général, la traduction de C ++ en object est la partie la plus longue du processus. De plus, une personne ne veut pas attendre que toutes les phases se terminent en cas d’erreur dans le code source.

Gardez l’esprit ouvert et attendez toujours la troisième alternative (option) .

Pour répondre à vos questions, veuillez noter que ceci est subjectif car il existe différents processeurs, différentes plates-formes, différents assembleurs et compilateurs C, dans ce cas, je vais parler de la plate-forme Intel x86.

  1. Les assembleurs ne comstacknt pas en pur binary, ce sont des codes machine bruts, définis avec des segments, tels que data, text et bss, pour n’en nommer que quelques-uns, ce qu’on appelle le code object. L’éditeur de liens intervient et ajuste les segments pour le rendre exécutable, c’est-à-dire prêt à être exécuté. Incidemment, la sortie par défaut lorsque vous comstackz en utilisant gcc est “a.out”, qui est un raccourci pour Assembler Output.
  2. Une directive spéciale a été définie pour les chargeurs de démarrage, à l’époque du DOS, il était courant de trouver une directive telle que .Org 100h , qui définit le code assembleur comme étant de l’ancienne variété .COM avant que la popularité de .EXE ne prenne de l’ampleur. De plus, vous n’aviez pas besoin d’un assembleur pour produire un fichier .COM, en utilisant l’ancien fichier debug.exe fourni avec MSDOS, réalisiez l’astuce pour les petits programmes simples, les fichiers .COM n’avaient pas besoin d’un éditeur de liens et format binary à exécuter. Voici une session simple utilisant DEBUG.
 1: * un 0100
 2: * mov AH, 07
 3: * int 21
 4: * cmp AL, 00
 5: * jnz 010c
 6: * mov AH, 07
 7: * int 21
 8: * mov AH, 4C
 9: * int 21
 dix:*
 11: * r CX
 12: * 10
 13: * n reply.com
 14: * w
 15: * q

Cela produit un programme .COM prêt à l’emploi appelé “respond.com” qui attend une frappe au clavier et ne le renvoie pas à l’écran. Notez, au début, l’utilisation de ‘a 100h’ qui montre que le pointeur d’instruction commence à 100h, ce qui est la caractéristique d’un .COM. Cet ancien script était principalement utilisé dans les fichiers de commandes en attente d’une réponse et non pas en écho. Le script original peut être trouvé ici .

Encore une fois, dans le cas des chargeurs de démarrage, ils sont convertis au format binary, il y avait un programme avec DOS, appelé EXE2BIN . Cela consistait à convertir le code object brut en un format pouvant être copié sur un disque amorçable pour le démarrage. N’oubliez pas qu’aucun éditeur de liens n’est exécuté sur le code assemblé, car l’éditeur de liens est destiné à l’environnement d’exécution et configure le code pour le rendre exécutable et exécutable.

Le BIOS lors du démarrage, attend que le code soit au segment: offset, 0x7c00, si ma mémoire me sert correctement, le code (après avoir été EXE2BIN’d), commencera à s’exécuter, puis le bootloader se déplacera émettre int 0x13 pour lire à partir du disque, allumer la porte A20, activer le DMA, passer en mode protégé car le BIOS est en mode 16 bits, puis les données lues sur le disque sont chargées en mémoire, le bootloader émet un saut dans le code de données (susceptible d’être écrit en C). C’est essentiellement la façon dont le système démarre.

Ok, le paragraphe précédent semble abstrait et simple, j’ai peut-être manqué quelque chose, mais c’est comme ça en quelques mots.

J’espère que ça aide, Cordialement, Tom.

Ils comstacknt en un fichier dans un format spécifique (COFF pour Windows, etc.), composé d’en-têtes et de segments, dont certains ont des codes d’opération “plain binary”. Les assembleurs et les compilateurs (tels que C) créent le même type de sortie. Certains formats, tels que les anciens fichiers * .COM, n’avaient pas d’en-tête, mais comportaient néanmoins certaines hypothèses (par exemple, où ils seraient chargés dans la mémoire ou quelle pourrait être leur taille).

Sur les machines Windows, le boostrapper du système d’exploitation se trouve dans un secteur de disque chargé par le BIOS, où ces deux éléments sont “simples”. Une fois que le système d’exploitation a chargé son chargeur, il peut lire les fichiers comportant des en-têtes et des segments.

Est ce que ça aide?

Pour répondre à la partie assemblée de la question, l’assembly ne comstack pas en binary, si je comprends bien. Assemblée === binary. Il traduit directement. Chaque opération d’assemblage a une chaîne binary qui lui correspond directement. Chaque opération a un code binary et chaque variable de registre a une adresse binary.

C’est-à-dire, à moins que l’assembleur! = Assemblée et que je comprenne mal votre question.

Il y a deux choses que vous pouvez mélanger ici. En général, il y a deux sujets:

  • Formats de fichier exécutables (voir la liste ici ), par exemple COFF, XCOFF, ELF
  • Langues intermédiaires , comme CIL ou GIMPLE ou bytecode

Ce dernier peut comstackr à la première en cours de assembly. Certains formats intermédiaires ne sont pas assemblés, mais exécutés par une machine virtuelle. Dans le cas de C ++, il peut être compilé dans CIL, qui est assemblé dans un assemblage .NET, d’où une certaine confusion.

Mais en général, C et C ++ sont généralement compilés en binary ou, en d’autres termes, dans un format de fichier exécutable.

Vous avez beaucoup de réponses à lire, mais je pense pouvoir restr bref.

“Code binary” fait référence aux bits qui transitent par les circuits du microprocesseur. Le microprocesseur charge chaque instruction de la mémoire en séquence, en faisant ce qu’il dit. Différentes familles de processeurs ont des formats différents pour les instructions: x86, ARM, PowerPC, etc. Vous pointez le processeur sur l’instruction de votre choix en lui donnant l’adresse de l’instruction en mémoire, puis il passe agréablement tout le rest du programme.

Lorsque vous voulez charger un programme dans le processeur, vous devez d’abord rendre le code binary accessible en mémoire afin qu’il ait une adresse en premier lieu. Le compilateur C génère un fichier dans le système de fichiers, qui doit être chargé dans un nouvel espace d’adressage virtuel. Par conséquent, en plus du code binary, ce fichier doit inclure les informations indiquant qu’il possède un code binary et à quoi doit ressembler son espace d’adressage.

Un chargeur de démarrage a des exigences différentes, son format de fichier peut donc être différent. Mais l’idée est la même: le code binary est toujours une charge utile dans un format de fichier plus grand, ce qui inclut au minimum une vérification de la validité pour s’assurer qu’il est écrit dans le jeu d’instructions correct.

Les compilateurs et les assembleurs C sont généralement configurés pour produire des fichiers de bibliothèque statiques. Pour les applications intégrées, vous êtes plus susceptible de trouver un compilateur qui produit quelque chose comme une image mémoire brute avec des instructions commençant à l’adresse zéro. Sinon, vous pouvez écrire un éditeur de liens qui convertit la sortie du compilateur C en tout ce que vous voulez.

Si je comprends bien, un chipset (CPU, etc.) aura un ensemble de registres pour stocker les données et comprendra un ensemble d’instructions pour manipuler ces registres. Les instructions seront des choses comme «stocker cette valeur dans ce registre», «déplacer cette valeur» ou «comparer ces deux valeurs». Ces instructions sont souvent exprimées sous la forme de codes alphabétiques faciles à utiliser (langage assembleur ou assembleur), correspondant aux nombres que le chipset comprend – ces nombres sont présentés à la puce en binary (code machine).

Ces codes sont le niveau le plus bas auquel le logiciel est confronté. Aller plus loin que cela entre dans l’architecture de la puce actuelle, ce à quoi je ne me suis pas impliqué.

Il y a beaucoup de réponses ci-dessus pour vous, mais j’ai pensé que j’appendais ces ressources qui vous donneront une idée de ce qui se passe. Fondamentalement, sous Windows et Linux, quelqu’un a essayé de créer le plus petit exécutable possible; sous Linux, ELF, windows, PE.

Les deux exécutent ce qui est supprimé et pourquoi et vous utilisez des assembleurs pour construire des fichiers ELF sans utiliser les options -felf qui le font pour vous.

J’espère que cela pourra aider.

Edit – vous pouvez également regarder l’assemblage d’un chargeur de démarrage comme celui de truecrypt http://www.truecrypt.org ou “stage1” de grub (le bit qui est réellement écrit dans le MDR).

Les fichiers exécutables (format PE sur Windows) ne peuvent pas être utilisés pour démarrer l’ordinateur car le chargeur PE n’est pas en mémoire.

La méthode d’amorçage fonctionne de la manière suivante: l’enregistrement d’amorçage principal sur le disque contient un blob de quelques centaines d’octets de code. Le BIOS de l’ordinateur (en ROM sur la carte mère) charge ce blob en mémoire et place le pointeur d’instruction du processeur au début de ce code de démarrage.

Le code de démarrage charge ensuite un chargeur «deuxième étape», sous Windows, appelé NTLDR (sans extension) à partir du répertoire racine. C’est un code machine brut qui, comme le chargeur MBR, est chargé en mémoire et exécuté.

NTLDR a la capacité complète de charger des fichiers PE, y compris des DLL et des pilotes.

С (++) (non géré) comstack vraiment en binary simple. Certains éléments liés au système d’exploitation – sont des appels de fonctions BIOS et OS, ils sont différents pour chaque système d’exploitation, mais toujours binarys.
1. Assembler comstack en pur binary, mais, aussi étrange que cela puisse paraître, il est moins optimisé que C (++)
2. Le kernel de l’OS, ainsi que le chargeur de démarrage, également écrit en C, donc pas de problème ici.

Java, Managed C ++ et autres fichiers .NET, comstacknt dans un pseudo-code (MSIL dans .NET), ce qui le rend inter-OS et multi-plateforme, mais nécessite l’exécution d’un interpréteur ou d’un traducteur local.