Question

Je suis fermement convaincu que l’un des éléments les plus importants de l’apprentissage d’une nouvelle langue n’est pas l’utilisation d’une nouvelle langue, mais bien la connaissance des concepts que vous en tirez. Je ne vous demande pas quelle est l’importance ou l’utilité de l’Assemblée. Je ne me soucie pas de ne jamais l’utiliser dans aucun de mes projets réels.

Ce que je veux savoir, c'est quels concepts d’Assemblée sont les plus importants pour tout programmeur général. Cela ne doit pas nécessairement être directement lié à Assembly - vous pouvez également penser que le programmeur habituel qui passe tout son temps dans des langages de niveau supérieur ne comprendrait pas ou ne prend pas pour acquis, tel que le cache du processeur.

Était-ce utile?

La solution

Je pense que le langage d'assemblage peut vous apprendre beaucoup de petites choses, ainsi que quelques grands concepts.

Je vais énumérer quelques éléments auxquels je peux penser ici, mais rien ne peut remplacer l’apprentissage, l’utilisation et l’utilisation de x86 et d’un jeu d’instructions RISC.

Vous pensez probablement que les opérations sur les entiers sont les plus rapides. Si vous voulez trouver une racine carrée entière d'un entier (par exemple, floor (sqrt (i))), il est préférable d'utiliser une routine d'approximation contenant uniquement des entiers, n'est-ce pas?

Nah. Le coprocesseur mathématique (sur x86) a une instruction fsqrt . La conversion en float, en prenant la racine carrée, et la conversion en int est encore plus rapide qu’un algorithme entier.

Ensuite, vous pouvez accéder à la mémoire, mais ne l'appréciez pas correctement, jusqu'à accéder à la mémoire jusqu'à ce que vous ayez plongé dans l'assemblage. Supposons que vous ayez une liste chaînée et que le premier élément de la liste contienne une variable à laquelle vous aurez besoin d'accéder fréquemment. La liste est rarement réorganisée. Eh bien, chaque fois que vous devez accéder à cette variable, vous devez charger le pointeur sur le premier élément de la liste, puis l'utiliser pour charger la variable (en supposant que vous ne pouvez pas conserver l'adresse de la variable dans un registre entre les utilisations). . Si vous stockez plutôt la variable en dehors de la liste, vous n’avez besoin que d’une opération de chargement unique.

Bien sûr, économiser quelques cycles ici et il n’est généralement pas important de nos jours. Mais si vous envisagez d’écrire du code qui doit être rapide, ce type de connaissances peut être appliqué à la fois avec l’assemblage en ligne et généralement dans d’autres langues.

Qu'en est-il des conventions d'appel? (Certains assembleurs s'occupent de cela pour vous - les vrais programmeurs n'utilisent pas ceux-ci.) L'appelant ou l'appelé nettoie-t-il la pile? Utilisez-vous même la pile? Vous pouvez transmettre des valeurs dans des registres - mais en raison du jeu d'instructions x86 amusant, il est préférable de passer certaines choses dans certains registres. Et quels registres seront conservés? Une chose que les compilateurs C ne peuvent pas vraiment optimiser par eux-mêmes est l’appel.

Il existe de petites astuces, comme insérer une adresse de retour, puis JMP dans une procédure; au retour de la procédure, il ira à l'adresse PUSHed. Ce changement par rapport à la manière habituelle de penser aux appels de fonctions est un autre de ces "états d'illumination". Si vous deviez concevoir un langage de programmation avec des fonctionnalités innovantes, vous devriez être au courant de choses amusantes dont le matériel est capable.

Une connaissance du langage d'assemblage vous apprend des choses spécifiques à l'architecture sur la sécurité informatique. Comment exploiter les dépassements de mémoire tampon ou passer en mode noyau et comment empêcher de telles attaques.

Ensuite, il y a l'énormité de l'auto-modification du code et, en tant que problème connexe, des mécanismes tels que les relocalisations et l'application de correctifs au code (cela nécessite également une étude du code machine).

Mais toutes ces choses ont besoin du bon type d’esprit. Si vous êtes le genre de personne qui peut mettre

while(x--)
{
  ...
}

utile une fois que vous avez appris ce qu’il fait, mais vous auriez du mal à comprendre ce que cela fait par vous-même, le langage d’assemblage est probablement une perte de temps.

Autres conseils

Enregistrer l'allocation et la gestion

Assembly vous donne une très bonne idée du nombre de variables (nombres entiers de la taille d'un mot machine) que le processeur peut jongler simultanément. Si vous pouvez décomposer vos boucles afin qu’elles ne comportent que quelques variables temporaires, elles s’inséreront toutes dans des registres. Sinon, votre boucle fonctionnera lentement au fur et à mesure que les choses seront échangées en mémoire.

Cela m’a vraiment aidé avec mon codage C. J'essaie de rendre toutes les boucles simples et serrées, avec le moins de spaghettis possible.

x86 est muet

L’apprentissage de plusieurs langages d’assemblage m’a fait comprendre à quel point le jeu d’instructions x86 est boiteux. Instructions de longueur variable? Difficile à prévoir le timing? Modes d'adressage non orthogonaux? Ugh.

Le monde serait meilleur si nous utilisions tous la technologie MIPS, je pense, ou même ARM ou PowerPC :-) processeurs MIPS à prix modique au lieu des processeurs x86 dotés de toutes ces qualités rédemptrices.

Il est bon de connaître le langage d'assemblage afin de mieux comprendre le fonctionnement de l'ordinateur "sous le capot", et cela aide lorsque vous déboguez quelque chose et que tout ce que le débogueur peut vous donner est une liste de code d'assemblage, ce qui vous donne au moins une chance de déterminer le problème. Cependant, essayer d'appliquer des connaissances de bas niveau à des langages de programmation de haut niveau, comme tirer parti de la façon dont le processeur cache les instructions, puis écrire du code de haut niveau pour forcer le compilateur à produire un code machine extrêmement efficace un signe que vous essayez de micro-optimiser. Dans la plupart des cas, il est généralement préférable de ne pas essayer de déjouer le compilateur, à moins que vous n'ayez besoin du gain de performance. Dans ce cas, vous pourriez aussi bien écrire ces bits dans l’assemblage.

Alors, il est bon de connaître l'assembly pour mieux comprendre le fonctionnement des choses, mais les connaissances acquises ne s'appliquent pas nécessairement directement à la manière dont vous écrivez du code dans des langages de haut niveau. Sur cette note, cependant, j'ai découvert qu'appréhender le fonctionnement des appels de fonction au niveau du code d'assemblage (en savoir plus sur la pile et les registres associés, sur la manière dont les paramètres sont transmis sur la pile, sur le fonctionnement de la mémoire automatique, etc.) en a fait une beaucoup plus facile à comprendre les problèmes que je rencontrais dans le code de niveau supérieur, tels que "out of stack stack" erreurs et "convention d'appel non valide" erreurs.

Le concept le plus important est SIMD et son utilisation créative. Une utilisation correcte de SIMD peut offrir d’énormes avantages en termes de performances dans une multitude d’applications allant du traitement des chaînes à la manipulation vidéo en passant par les mathématiques matricielles. C’est là que vous pouvez obtenir plus de performances multipliées par 10 par rapport au code C pur - c’est pourquoi l’assemblage reste utile au-delà du simple débogage.

Quelques exemples du projet sur lequel je travaille (tous les nombres sont des comptes de cycle d'horloge sur un Core 2):

DCT H.264 8x8 inverse (transformation de fréquence):

c: 1332
mmx: 187
sse2: 127

Compensation de mouvement chroma 8x8 (filtre d'interpolation bilinéaire):

c: 639
mmx: 144
sse2: 110
ssse3: 79

4 16x16 Opérations de somme des différences absolues (recherche de mouvement):

c: 3948
mmx: 278
sse2: 231
ssse3: 215

(oui, c'est vrai - plus de 18 fois plus vite que C!)

Erreur quadratique moyenne d'un bloc 16x16:

c: 1013
mmx: 193
sse2: 131

Variance d'un bloc 16x16:

c: 783
mmx: 171
sse2: 106

Mémoire, registres, sauts, boucles, décalages et les différentes opérations que l’on peut effectuer en assembleur. Je ne manque pas le temps de déboguer mes programmes de classe d'assemblage - ils étaient douloureux! - mais cela m’a certainement donné de bonnes bases.

Nous oublions (ou ne savions peut-être jamais) que toutes ces affaires de pantalons de fantaisie que nous utilisons aujourd'hui (et que j'adore!) se résument à toutes ces choses à la fin.

Maintenant, nous pouvons certes avoir une carrière productive et lucrative sans connaître les assembleurs, mais je pense que ces concepts sont intéressants à connaître.

Je dirais que l’apprentissage de la récursivité et des boucles en assemblage m’a beaucoup appris. Cela m'a fait comprendre le concept sous-jacent de la façon dont le compilateur / interprète de la langue que je suis utilise place les éléments dans une pile et les affiche au fur et à mesure de leurs besoins. J'ai aussi appris à exploiter le fameux débordement de pile. (ce qui reste étonnamment facile en C avec quelques commandes get et put).

Hormis l'utilisation d'ASM dans des situations de tous les jours, je ne pense pas que j'utiliserais les concepts que l'assemblage m'a appris.

Je dirais que les modes d'adressage sont extrêmement importants.

Mon alma mater a poussé cela à l'extrême, et comme x86 n'en avait pas assez, nous avons tout étudié sur un simulateur de PDP11 qui devait en avoir au moins sept dont je me souvienne. Rétrospectivement, c'était un bon choix.

timing

exécution rapide:

  • traitement parallèle
  • instructions simples
  • tables de consultation
  • prévision de branche, traitement en pipeline

rapide pour ralentir l'accès au stockage:

  • enregistre
  • cache et différents niveaux de cache
  • pile de mémoire et pile
  • mémoire virtuelle
  • E / S externe

De nos jours, x86 asm n’est pas une ligne directe vers les entrailles de la CPU, mais plutôt une API. Les codes d'opération d'assembleur que vous écrivez sont eux-mêmes compilés dans un jeu d'instructions complètement différent, réorganisé, réécrit, corrigé et généralement mutilé au-delà de la reconnaissance.

Ce n’est donc pas comme si l’apprentissage d’assembleur vous fournissait un aperçu fondamental de ce qui se passait dans la CPU. IMHO, plus important que d’apprendre à assembler, c’est de bien comprendre le fonctionnement du processeur cible et de la hiérarchie de la mémoire.

Cette série d'articles couvre de manière assez approfondie ce dernier sujet.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top