Pourquoi les compilateurs produisent-ils du code assembleur?

19

Le langage d'assemblage est converti en langage machine par l'assembleur. Pourquoi un compilateur convertirait-il un langage de haut niveau en assembleur? Ne peut-il pas convertir directement du langage de haut niveau en code machine?

CODERSAM
la source

Réponses:

22

Les autres compilateurs doivent produire un assemblage plutôt qu'un code machine approprié:

  • Les adresses symboliques utilisées par les assembleurs au lieu des adresses de machine à codage en dur facilitent la relocalisation du code .
  • La liaison de code peut impliquer des contrôles de sécurité tels que la vérification de type, et c'est plus facile à faire avec des noms symboliques.
  • Les petits changements dans le code machine sont plus faciles à accepter en changeant l'assembleur plutôt que le générateur de code.
Martin Berger
la source
pourquoi le langage d'assemblage est si efficace, bien qu'il soit également écrit en anglais et comment le processeur le comprend?
CODERSAM
3
@CODERSAM Assembly est un langage formel, pas un langage naturel. Il est très proche du langage machine. La traduction n'introduit donc pas d'inefficacité.
Martin Berger
quand vous dites "très proche du langage machine", qu'est-ce que cela signifie? Je suis vraiment confus avec ça!
CODERSAM
2
@CODERSAM La signification précise est compliquée, mais quelque chose comme l'homomorphisme en algèbre. Lorsque vous traduisez, dites "ajouter eax, # 2" qui est un assemblage x86, vous pouvez le traduire en d7f5 (ou quoi que puisse être le code op), tout de suite, sans regarder le contexte, sans ajouter d'autres éléments. L'assemblage n'a pas d'abstraction.
Martin Berger
1
"L'assemblage n'a pas d'abstraction" - je dirais que les noms d'étiquette sont déjà une abstraction (à partir de décalages). En outre, le contexte joue un rôle: par exemple, il add eax,2peut être traduit en 83 c0 02ou en 66 83 c0 02, selon la dernière directive en date comme use16.
Ruslan
15

Un compilateur convertit généralement le code de haut niveau directement en langage machine, mais il peut être construit de manière modulaire de sorte qu'un back-end émette du code machine et l'autre code assembleur (comme GCC). La phase de génération de code produit du "code" qui est une représentation interne du code machine, qui doit ensuite être converti en un format utilisable comme le langage machine ou le code assembleur.

Yuval Filmus
la source
En outre, si la source peut inclure du code d'assembly, un mécanisme doit être disponible pour traduire de toute façon cet assembly en ligne.
Paul A. Clayton
pourquoi le langage d'assemblage est si efficace, bien qu'il soit également écrit en anglais et comment le processeur le comprend?
CODERSAM
1
La langue de l'assemblage est une description "anglaise" du code machine.
Yuval Filmus
11

Historiquement, un certain nombre de compilateurs notables ont généré directement du code machine. Il y a cependant quelques difficultés à le faire. Généralement, quelqu'un qui essaie de confirmer qu'un compilateur fonctionne correctement trouvera plus facile d'examiner la sortie du code assembleur que le code machine. De plus, il est possible (et c'était historiquement courant) d'utiliser un compilateur C ou Pascal en un seul passage pour produire un fichier en langage assembleur qui peut ensuite être traité à l'aide d'un assembleur en deux passes. La génération directe de code nécessiterait soit l'utilisation d'un compilateur C ou Pascal en deux passes, soit l'utilisation d'un compilateur en un seul passage suivi de certains moyens de patcher en arrière les adresses de saut avant [si un environnement d'exécution rend la taille d'un programme lancé disponible dans un tache fixe, un compilateur pourrait écrire une liste de correctifs à la fin du code et demander au code de démarrage d'appliquer ces correctifs au moment de l'exécution; une telle approche augmenterait la taille de l'exécutable d'environ quatre octets par point de patch, mais améliorerait la vitesse de génération du programme].

Si l'objectif est d'avoir un compilateur qui s'exécute rapidement, la génération directe de code peut bien fonctionner. Pour la plupart des projets, cependant, le coût de génération du code en langage assembleur et de son assemblage n'est vraiment pas un problème majeur de nos jours. Le fait que les compilateurs produisent du code sous une forme pouvant interagir agréablement avec le code produit par d'autres compilateurs est généralement un avantage suffisamment important pour justifier l'augmentation des temps de compilation.

supercat
la source
1

Même les plates-formes qui utilisent le même jeu d'instructions peuvent avoir différents formats de fichiers d'objets déplaçables. Je peux penser à "a.out" (début UNIX), OMF, MZ (EXE MS-DOS), NE (Windows 16 bits), COFF (UNIX System V), Mach-O (OS X et iOS), et ELF (Linux et autres), ainsi que des variantes de ceux-ci, tels que XCOFF (AIX), ECOFF (SGI) et exécutable portable (PE) basé sur COFF sur Windows 32 bits. Un compilateur qui produit un langage d'assemblage n'a pas besoin d'en savoir beaucoup sur les formats de fichier objet, ce qui permet à l'assembleur et à l'éditeur de liens d'encapsuler ces connaissances dans un processus distinct.

Voir aussi Différence entre OMF et COFF sur débordement de pile.

Damian Yerrick
la source
1

Habituellement, les compilateurs travaillent en interne avec des séquences d'instructions. Chaque instruction sera représentée par une structure de données représentant son nom d'opération, ses opérandes, etc. Lorsque les opérandes sont des adresses, ces adresses sont généralement des références symboliques et non des valeurs concrètes.

L'assembleur de sortie est relativement simple. Il s'agit à peu près de prendre la structure de données interne du compilateur et de la vider dans un fichier texte dans un format spécifique. La sortie de l'assembleur est également relativement facile à lire, ce qui est utile lorsque vous devez vérifier ce que fait le compilateur.

La sortie de fichiers d'objets binaires représente beaucoup plus de travail. Le rédacteur du compilateur doit savoir comment toutes les instructions sont codées (ce qui peut être loin d'être trivial sur certains CPUS), il doit convertir certaines références symboliques en adresses relatives de compteur de programme et d'autres en une certaine forme de métadonnées dans le fichier objet binaire . Ils doivent tout écrire dans un format hautement spécifique au système.

Oui, vous pouvez absolument créer un compilateur capable de produire des objets binaires directement sans écrire l'assembleur comme étape intermédiaire. La question comme tant de choses dans le développement de logiciels est de savoir si la réduction du temps de compilation vaut le travail de développement et de maintenance supplémentaire.

Le compilateur que je connais le mieux (freepascal) peut générer un assembleur sur toutes les plates-formes, mais uniquement des objets binaires directement sur un sous-ensemble de plates-formes.

Peter Green
la source
1

Un compilateur devrait être en mesure de produire une sortie d'assembleur en plus du code normal relocalisable à l'avantage du programmeur.

Une fois, je n'ai tout simplement pas trouvé le bogue dans un programme C fonctionnant sous Unix System V sur une machine LSI-11. Rien ne semblait fonctionner. Enfin, désespéré, le compilateur C protable a excrété une version assembleur de sa traduction. J'avais enfin trouvé le bug! Le compilateur allouait plus de registres qu'il n'en existait dans la machine! (Le compilateur a alloué les registres R0 à R8 sur une machine avec uniquement les registres R0 à R7.) J'ai réussi à contourner le bogue dans le compilateur et mon programme a fonctionné.

Un autre avantage de la sortie d'assembleur est d'essayer d'utiliser des bibliothèques "standard" qui utilisent des protocoles de passage de paramètres différents. Plus tard, les compilateurs C me permettent de définir le protocole avec un paramètre ("pascal" obligerait le compilateur à ajouter les paramètres dans l'ordre donné par opposition à la norme C d'inversion de l'ordre).

Encore un autre avantage est de permettre au programmeur de voir ce que fait un compilateur épouvantable. Une simple instruction C prend environ 44 instructions machine. Les valeurs sont chargées de la mémoire, puis rapidement supprimées. etc, etc, etc ...

Personnellement, je crois qu'avoir un compilateur au lieu d'un module objet déplaçable est vraiment stupide. Lors de la compilation de votre programme, le compilateur rassemble de nombreuses informations sur votre programme. Il stocke généralement toutes ces informations dans quelque chose appelé une table de symboles. Après avoir excrété le code assembleur, il jette toute cette table d'informations. L'assembleur examine ensuite le code excrété et recueille une partie des informations que le compilateur possédait déjà. Cependant, l'assembleur ne sait rien des instructions If des instructions For ou While. Il manque donc toutes ces informations. L'assembleur produit ensuite le module d'objet déplaçable que le compilateur n'a pas fait.

Pourquoi???

Robert Pearson
la source