ebook img

Sommaire Éditorial Article 2D/3D/Jeux Article Réseau PDF

108 Pages·2014·28.99 MB·French
by  
Save to my drive
Quick download
Download
Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.

Preview Sommaire Éditorial Article 2D/3D/Jeux Article Réseau

Édition d’août – septembre 2014 Numéro 53 Magazine en ligne gratuit Diffusion de copies conformes à l’original autorisée Réalisation : Alexandre Pottiez & Sébastien Lataix Rédaction : la rédaction de Developpez Contact : [email protected] Sommaire Assembleur Page 2 Article 2D/3D/Jeux Eclipse Page 11 Java Page 22 JavaScript Page 28 AJAX Page 50 2D/3D/Jeux Page 54 Commençons... avec des cercles Reseau Page 75 OpenOffice-LibreOffice Page 94 La création de ses propres graphismes est une nécessité pour LaTeX Page 99 la plupart des développeurs indépendants. Nous allons essayer de commencer avec des idées basiques et des exercices pour améliorer ces notions. par Alexandre Laurent Éditorial Page 70 Le magazine des développeurs est Article Réseau deretouravecdenouveauxarticles, denouvellesrubriques,denouvelles news. La rédaction est heureuse de vous présenter un florilège de ses meilleures ressources. Modélisation en couche des protocoles réseau L’objectif de cet article est d’introduire les concepts de modélisation, de présenter les deux modélisations dominantes et le « dénominateur commun » qui en est issu. par Philippe Latu Page 93 La rédaction Assembleur Les derniers tutoriels et articles L’assembleur en ligne Ce tutoriel va vous présenter l’assembleur en ligne avec le langage C et le compilateur 1 Introduction Aujourd’hui,lelangageassembleurestassezpeu bleur dans leurs programmes. utilisé. La plupart des programmeurs utilisent les L’assembleur en ligne, Inline Assembly, est une langages haut niveau, comme le C ou le C++, pour extension des langages de programmation haut ni- plusieursraisons.Enpremierlieu,parcequeceslan- veau standard offerte par certains compilateurs. Il gages permettent d’écrire des programmes indépen- permet d’inclure des instructions assembleur dans dantsdel’architecture,etdoncportables.Ensecond un programme écrit en langage haut niveau. lieu, parce qu’ils présentent des syntaxes simples et compréhensibles, ce qui permet d’augmenter la Ce tutoriel va vous présenter l’assembleur en productivité, lors de l’écriture et la maintenance ligne avec le langage C et le compilateur GCC. Les du code. Mais, de temps en temps, les program- différentsexemplescitéssonttéléchargeablessurDe- meurs ont besoin d’utiliser des instructions assem- veloppez.com : lien 1. 2 Quand utiliser l’assembleur en ligne? L’ajoutdesinstructionsassembleurdépendantes sortie(x86 :instructionsOUT,OUTS,IN,INS).On de l’architecture à un programme écrit dans un lan- peut aussi citer les instructions de gestion de la mé- gage haut niveau affecte sa portabilité. Ainsi, vous moire (x86 : LLDT, LGDT...) et des tâches (x86 : ne devriez utiliser des instructions assembleur qu’en LTR). dernier ressort. Par exemple, lorsque vous consta- L’utilisation des instructions assembleur néces- tezquel’utilisationdel’assembleurvaoptimiservos site une connaissance avancée de l’architecture et codes et vous produira un programme rapide, ou du fonctionnement interne du compilateur. En ef- lorsque vous voulez utiliser des instructions spéci- fet, l’assembleur en ligne est largement utilisé par fiques à l’architecture et non descriptibles par une les développeurs des systèmes d’exploitation et des syntaxe de haut niveau. pilotes de périphériques (drivers). En fait, la capacité d’optimisation des compila- Dans ces domaines de programmation, la porta- teurs est limitée à cause de plusieurs facteurs, tels bilité d’un code n’est pas une exigence extrême et queleurcompréhensionlimitéeducomportementdu n’a parfois pas de sens. En effet, le code source d’un code,etlecontextedanslequelilserautilisé,etaussi driver ou d’un système d’exploitation ne pourra ja- le besoin des programmeurs d’effectuer la compila- mais être portable. La haute priorité est, souvent, tion rapidement. En effet, la tâche d’optimisation donnéeàlaproductiond’unprogrammeperformant estcoûteuseenmémoireetentempsdecompilation. qui s’exécute rapidement et qui permet d’exploiter Ainsi, la substitution des parties complexes du code efficacement toutes les fonctionnalités d’une archi- etsensiblesàlaperformanceduprogrammepardes tecture donnée. simples instructions assembleur va simplifier l’opti- Pour les systèmes d’exploitation, le terme misation d’une part, et permettra de produire un multiplate-forme est plus précis. Par exemple, le programme performant et rapide, d’autre part. système Linux est multiplate-forme parce qu’il peut En outre, plusieurs fonctionnalités des proces- tournersurunevariétéd’architectures.Enfait,dans seurs sont encore difficiles à décrire par une syntaxe lecodesourcedesonnoyau,chaquearchitecturepos- dehautniveau.Ainsi,plusieursinstructionsmachine sède sa propre description en langage C et en as- doiventêtreécritesàlamain.Parmicelles-ci,oncite sembleur (/usr/src/linux/arch/). Cela vient du fait lesinstructionssystèmed’accèsauxportsd’entrée/- que les instructions et les caractéristiques diffèrent Developpez Magazine est une publication de developpez.com page 2 Numéro 52 Juin–Juillet 2014 d’une architecture à une autre. Autrement dit, le des instructions assembleur x86. Par exemple, le fi- code source dépendant d’une architecture ne peut chier io.h contient les instructions x86 d’accès aux pas être compilé pour tourner sur une autre. ports d’entrée/sortie. En outre, le fichier string.h Les instructions assembleur sont souvent encap- contient l’implémentation des opérations de mani- sulées dans des macros ou des fonctions en ligne dé- pulationdeschaînesenutilisantlejeud’instructions finies dans des fichiers d’en-tête. C’est pour faciliter x86. la maintenance du code source et pour faciliter son portage d’une architecture à une autre. Consultez Danscetutoriel,onvaétudierquelquesexemples le répertoire /usr/src/linux/arch/x86/include/asm des codes assembleur pris du code source du noyau pour avoir accès à des exemples de code contenant Linux 0.01. Vous pouvez le télécharger ici : lien 2. 3 L’assembleur en ligne avec le langage C En particulier, le compilateur GCC, GNU Com- sur l’assembleur restera valide et vous en aurez be- pilers Collection dispose d’une syntaxe simple et soin. Vous allez juste apprendre une syntaxe complète permettant d’utiliser efficacement des ins- qui vous permettra d’écrire des instructions tructions assembleur dans un programme C. assembleur dans un programme C. Dans un programme assembleur classique, Avec le compilateur GCC, les instructions as- chaque instruction possède, typiquement, deux opé- sembleur, ainsi que la définition de leurs opérandes, randes : un opérande source et un opérande desti- doivent être encapsulées dans une construction dé- nation. Ces opérandes peuvent être utilisés de fa- clarée,typiquement,aveclemotcléasm.Celavain- çon explicite ou implicite. On peut citer comme diquer au compilateur que le code à l’intérieur doit exemplel’instructionx86MOV,quiutiliseexplicite- être traité d’une façondifférente. Pendant la compi- mentdeuxopérandes.EnutilisantlasyntaxeAT&T, lation, le compilateur GCC va utiliser les informa- on peut écrire cette instruction comme suit : tionsinclusesdanslaconstructionasm pourgénérer lesinstructionsassembleuretlesplacerdanslecode- 1 MOV source, destination cible. Les opérandes peuvent être de trois types : registre, Notez bien que GCC utilise par défaut la syn- mémoire ou immédiat. Dans l’exemple ci-dessous, taxe AT&T pour générer le code-cible. En effet, l’instruction MOV va transférer le contenu du re- le compilateur utilise, par défaut, le programme as gistre EDX dans EAX : (GNU Assembler)pourgénérerlecodeobjet.Ainsi, 1 MOV EDX, EAX dans la construction asm, les instructions assem- Avecl’assembleurenligne,onnevapasréinventerla bleur doivent être écrites en utilisant cette syntaxe, roue, croyez-moi! Les instructions seront écrites de àmoinsquevousn’utilisiezl’option-masm ducom- la même façon, sauf que les opérandes seront définis pilateur. Dans ce qui suit, on va utiliser la syntaxe séparémentetleursvaleurspourrontêtredesexpres- AT&T. Voici un tutoriel qui va vous aider à l’ap- sionsC.Autrementdit,touscequevousavezappris prendre rapidement : lien 3 4 Syntaxe de la construction asm Le mot clé asm doit être suivi par une expres- variable a (a = b;) : sion entre parenthèses et constituée de sections sé- 1 #include <stdio.h> paréespardeuxpoints.Lapremièresectioncontient 2 int main(void) des instructions assembleur écrites entre guillemets. 3 { Dansladeuxième,ondoitspécifierlesopérandesde 4 int a = 10; sortiedesinstructions.Latroisièmesectioncontient 5 int b = 5; 6 les opérandes d’entrée. La quatrième section sert à 7 __asm__("movl\t%1, %0" déclarerlesmodificationsapportées,surlesregistres 8 ou en mémoire, par les instructions. 9 : "=&r" (a) : "r" (b) 10 : /* liste des modifications */ 11 ); Important : vous devez toujours 12 placer les deux points qui séparent 13 printf("a = b = %d \n", a); la deuxième section de la troisième, 14 return 0; mêmesilasectiondesortiesestvide. 15 } Ici,chaqueopérandeestécritcommeuneexpression Leprogrammesuivantutilisel’instructionassem- C placée entre parenthèses et précédée d’une chaîne bleur movl pour affecter la valeur de la variable b à de caractères indiquant sa contrainte. La lettre r Developpez Magazine est une publication de developpez.com page 3 Numéro 52 Juin–Juillet 2014 dans chaque contrainte symbolise le nom d’un re- 5 subl $16, %esp gistre général du processeur. Ainsi, le compilateur 6 #APP GCC va allouer un registre de ce type, pour sto- 7 # 9 "movl.c" 1 8 movl %edx, %eax cker la valeur (5) de la variable b, et un autre pour 9 # 0 "" 2 stocker celle (10) de a. Le caractère « = » dans la 10 #NO_APP contrainte "=r" du premier opérande indique que 11 movl $.LC0, (%esp) c’est un opérande de sortie. Toutes les contraintes 12 movl %eax, 4(%esp) 13 call printf des opérandes de sortie doivent commencer par « = 14 xorl %eax, %eax ». 15 leave Note : le caractère « & » dans Dans le code-cible, le bloc asm est placé entre les la première contrainte va indiquer deuxlignesdecommentaires#APP et#NO_APP. au compilateur de ne pas allouer le Lecompilateuraallouédeuxregistresgénérauxpour même registre pour les deux opé- stocker les valeurs de a et b : le registre EAX pour randes. L’utilisation de ce caractère a et le registre EDX pour b. dans l’exemple ci-dessus n’est pas obligatoire, mais dans certains cas il 4.1 Les instructions assembleur est très important. On va expliquer, en détails,son utilisation dansla sec- La première section de la construction asm tion 4.5. Déclaration des modifica- contient les instructions assembleur. Dans cette sec- tions. tion, vous devez spécifier un modèle d’instructions assembleur,unpeucommecequiapparaîtdansune Pour se référer aux opérandes dans le code as- description machine (un fichier .s). sembleur, on peut écrire leurs indices précédés du EnutilisantlasyntaxeAT&T,sivousvoulezuti- caractère « % ». Ainsi, l’instruction movl va trans- liserlenomd’unregistrecommeopérande,préfixez- férerlecontenu(5)dudeuxièmeopérande(sourceou lepar«%% ».Pourseréféreràunopéranded’entrée entrée d’indice 1) dans le registre alloué au premier ou de sortie, dans une instruction assembleur, écri- opérande (destination ou sortie d’indice 0). vez le caractère « % » suivi de son indice (0, 1... 29). Important :laproductiondesorties Comme dans un code assembleur classique, les aura lieu, toujours, après l’exécution instructionsdeasm doiventêtreséparéespardessé- de la dernière instruction du code as- parateurs. En assembleur GNU, on a le choix d’uti- sembleur. liser soit le caractère «; », soit le caractère saut de ligne. Si vous choisissez ce dernier, placez « \n » Danslecodeci-dessus,aprèsl’exécutiondel’ins- après chaque instruction, sauf la dernière. truction movl, la sortie a sera produite. C’est en af- Notez que vous pouvez mettre plusieurs instruc- fectant le contenu du registre destination à la va- tions dans la même chaîne, en les séparant par des riable a. «; », comme suit : GCC ne peut pas analyser les instructions as- sembleuretvérifiersiellessontvalidesounon.Ainsi, 1 __asm__("\tnop;nop;nop\t" il ne peut pas vérifier si le type des opérandes est 2 "jmp \t1f\n" 3 "1:" ::); raisonnable pour les instructions ou non. En fait, c’est le rôle de l’assembleur as. En ce qui concerne Le « \n » sera traduit en un saut de ligne dans le laconstructionasm,GCC vajuste,dansunpremier code-cible.Lecaractère«\t »estoptionneletilsera temps, vérifierla syntaxedes expressions Cutilisées traduit en une tabulation. comme opérandes. Ensuite, il va générer les opé- Pendantlacompilation,GCC utiliselesinforma- randes des instructions en utilisant les informations tions(surlesopérandes)contenuesdanslessections contenues dans les sections d’entrées et de sorties. d’entréesetdesortiespourgénérerlesopérandesdes Finalement, il va placer les instructions assembleur instructions assembleur. avec leurs opérandes dans le code-cible. Enfin, pour obtenir le code-cible produit par le 4.2 Les opérandes compilateurGCC,faites-luipasserl’option-S.Faites Chaque opérande peut être écrit comme une passer, également, l’option -O2, pour appliquer le expression C placée entre parenthèses et précédée deuxième niveau d’optimisation de GCC à votre d’une chaîne de caractères indiquant sa contrainte. code. Voici une portion du code-cible de l’exemple Engénéral,lesinstructionsassembleurutilisenttrois ci-dessus : types d’opérandes : les opérandes registre, les opé- 1 movl $5, %edx randes mémoire et les opérandes immédiats. Dans 2 movl %esp, %ebp la construction asm, les contraintes vont préciser si 3 .cfi_def_cfa_register 5 un opérande doit être stocké dans un registre, et 4 andl $-16, %esp Developpez Magazine est une publication de developpez.com page 4 Numéro 52 Juin–Juillet 2014 quel type de registre; si l’opérande doit être une tive#define ouunevariableCdetypeconst comme référence dans la mémoire, et quel type d’adresse opérande de sortie. Le compilateur vérifie cela pour utilisé; si l’opérande est une constante immédiate, chaque opérande de sortie. et quelle valeur elle peut avoir. Une contrainte peut Un opérande de sortie ordinaire est en écri- être constituée d’un ou plusieurs modificateurs et ture seulement. Ainsi, les contraintes de sortie lettres. contiennent, souvent, le modificateur « = ». La va- leur d’un tel opérande reste indéterminée jusqu’à la production des sorties! Vous pouvez vérifier cela 4.2.a Les lettres dans l’exemple movl.c, en inversant l’ordre des opé- Les lettres spécifient souvent les registres d’une randes de l’instruction comme suit : architecture donnée. Le tableau suivant liste les lettrescourammentutiliséesavecl’architecturex86 : 1 __asm__("movl\t%0, %1" 2 Lettre Registre 3 : "=&r" (a) EAX, EBX, ECX, 4 : "r" (b) R EDX,ESI,EDI,ESP 5 :/* liste des modifications */ et EBP 6 ) q EAX, EBX, ECX, Ainsi, si vous décidez d’utiliser un opérande de EDX (mode 32 bits) sortieenlectureetenécriture,vousdevezutiliserle a Registre EAX modificateur « + » à la place de « = ». b Registre EBX c Registre ECX d Registre EDX 4.4 Les entrées S Registre ESI Lesopérandesd’entréeoccupentlatroisièmesec- D Registre EDI tion de la construction asm. Ils sont traités de ma- Combinaison A nière différente de celles de sortie, bien qu’ils aient EAX :EDX la même syntaxe. Il existe aussi un ensemble de lettres commun à Contrairement aux opérandes de sortie, un opé- toutes les architectures. Consultez le manuel de rande d’entrée est par défaut en lecture et en écri- GCC (à cette adresse : lien 4) pour avoir accès à la ture (sans utiliser le « + »). Ainsi, vous pouvez liste complète de contraintes. Avec l’architecture x86, on utilise souvent la spécifier une même location (registre ou mémoire) comme opérandes de sortie et d’entrée à la fois. La contrainte « r » ou « R » pour spécifier un opé- connexionentrelesdeuxopérandesdoitêtredécrite rande registre, la contrainte « m » pour spécifier un par une contrainte disant que les deux opérandes opérande mémoire et la contrainte « i » ou « I » pour spécifier un opérande immédiat. doivent occuper la même location à l’exécution de l’instruction correspondante. Notez qu’on peut uti- En outre, un nombre (0, 1, 2... 9) peut être uti- liserlamêmeexpressionCpourlesdeuxopérandes, lisé dans la contrainte d’un opérande d’entrée, pour commeonpeututiliserdeuxexpressionsdifférentes. dire que cet opérande fait référence à un opérande Pour illustrer, prenons l’exemple suivant : de sortie. Ainsi, le compilateur va allouer la même location pourstockerlesvaleursdesdeuxopérandes. 1 __asm__( "addl %2, %1" : "=r" (a) : "0" (a), "r"(b)); 4.2.b Les modificateurs Lacontrainte"0" danslepremieropéranded’entrée (d’indice 1) dit que l’expression C doit occuper le Pour les modificateurs, on a déjà vu le modifica- même registre général que celui spécifié dans l’opé- teur « = ». Il en existe cinq autres, parmi lesquels rande de sortie (d’indice 0). on cite les modificateurs « + » et « & ». Le premier indique que l’opérande est en écriture et en lecture Important : un nombre n’est auto- à la fois. Le modificateur « & » a une utilisation risé comme contrainte que dans un spécifique, qu’on va expliquer dans les sections sui- opérande d’entrée et il doit se référer vantes. à un opérande de sortie. 4.3 Les sorties Seul un nombre dans une contrainte peut garan- La deuxième section de la construction asm tir que deux opérandes vont occuper la même lo- contientlesopérandesdesortie,séparéspardesvir- cation. L’utilisation de la même expression dans les gules. Chaque opérande doit être une expression C deux opérandes ne suffit pas. Ainsi, le résultat du de type lvalue. C’est-à-dire qu’on peut le mettre à code suivant n’est pas fiable : gauche d’une affectation. Par exemple, vous ne de- 1 __asm__( "addl %2, %1" : "=r" (a) : "r" vez pas utiliser une constante déclarée avec la direc- (a), "r"(b)); Developpez Magazine est une publication de developpez.com page 5 Numéro 52 Juin–Juillet 2014 En fait, Le compilateur peut choisir deux registres stocker les valeurs des opérandes d’entrée et de sor- généraux différents pour stocker les deux opérandes tie.Donc,onn’apaslistéleursnomsdanslasection 0 et 1. 4 de la construction asm. En utilisant les informations sur la modification des registres, le compilateur détermine les valeurs 4.5 Déclaration des modifications qui doivent être sauvegardées dans la pile et restau- Si une instruction modifie (explicitement ou im- rées après l’exécution du bloc asm. plicitement) les valeurs d’un ou plusieurs registres, spécifiezcesregistresdanslaquatrièmesectiondela constructionasm.Lesregistresmodifiéssontdécrits 4.5.a Modification de la mémoire : "me- dans des chaînes de caractères séparées par des vir- mory" gules. Dans l’exemple suivant, la valeur du registre Si vos instructions assembleur accèdent à la mé- EBX est modifiée par l’instruction movl. Donc, on moired’unemanièreimprévisibleetarbitraire,ajou- doit écrire son nom dans la section 4 de la construc- tion asm : tez "memory" à la liste des modifications. Cela va renseigner à GCC de ne pas maintenir les valeurs 1 #include<asm/unistd.h> /* (destinéesàêtrechargéesdanslamémoire)stockées __NR_write */ dans des registres et de ne pas optimiser l’accès 2 #include<unistd.h> /* à la mémoire, durant l’exécution des instructions. STDOUT_FILENO */ 3 #include<string.h> /* D’autre part, si vous connaissez la taille de la mé- strlen() */ moire accédée, ajoutez-la comme entrée, sinon utili- 4 sez "memory". 5 #define STDOUT STDOUT_FILENO 6 7 int main(void) 8 { 4.5.b Modification du registre code condi- 9 char * msg = "hello!\n"; tion : "cc" 10 int res; 11 Si vos instructions assembleur peuvent modifier 12 __asm__("movl \t%2, %%ebx\n\t" 13 "int \t$0x80" le registre de code condition cc d’une manière in- 14 habituelle, ajoutez "cc" à la liste de modifications. 15 :"=a" (res) Avec l’architecture x86, la notation cc est utilisée 16 :"0" (__NR_write), "I" (STDOUT) parGCC pourreprésenterleregistredesindicateurs , 17 "c" (msg), "d" (strlen(msg)) EFLAGS. 18 :"ebx"); Certaines instructions de l’architecture x86, 19 telles que celles de décalage et de rotation logique 20 return 0; ouarithmétique,peuventaltérerquelquesbitsdure- 21 } gistre EFLAGS pendant leur exécution. Pour illus- L’instruction assembleur int utilise, implicitement, trer, soit l’exemple suivant : les registres EAX, EBX, ECX et EDX. Le registre ECX contient l’adresse du premier caractère de la 1 __asm__( "shll $2, %1" : "=r" (res) : "r chaîne msg, et EDX contient sa taille. Le registre " (a) : "cc"); EAX est utilisé par l’instruction int comme opé- randesd’entréeetdesortieàlafois.Entantqu’opé- Dans l’exemple ci-dessus, l’instruction shll (Logical rande d’entrée, il doit être initialisé avec la valeur Left Shift) décale les bits du registre deux positions vers la gauche. Le dernier bit (de gauche) décalé est numérique __NR_write. Ainsi, l’instruction int va générer l’appel système 4 (la fonction write() du fi- transféré dans le bit CF (Carry Flag). Ainsi, le re- chier /usr/include/unistd.h), pour afficher le mes- gistre code condition (EFLAGS) est toujours mo- sage«hello!»surlaconsole.Lavaleurderetourde difié avant qu’on puisse le tester! Donc, "cc" doit être placé dans la section 4 pour renseigner le com- l’appel système sera stockée dans le registre EAX, en tant qu’opérande de sortie. pilateur. Par contre, le bit OF (Overflow Flag) sera modifié automatiquement par le processeur comme Important : vous ne devez jamais résultat de l’exécution de shll, ce qui n’est pas pris écrirelenomd’unregistredanslasec- en compte par le compilateur comme modification tiondedéclarationdesmodifications, du registre de code condition cc. siceregistrefaitpartied’unopérande Les instructions de test TEST, de comparaison d’entrée ou de sortie. CMP,ainsiquelesinstructionsdecontrôledesindi- cateurs comme CLD et STD n’ont pas d’opérandes En fait, un tel registre est, à l’avance, déclaré de sortie (comme shll). Ainsi, ils ne sont pas consi- modifié. Dans l’exemple ci-dessus, les registres ECX dérésparlecompilateurcommemodificateursdere- (”c”), EDX (”d”) et EAX (”=a”) sont utilisés pour gistre cc. Developpez Magazine est une publication de developpez.com page 6 Numéro 52 Juin–Juillet 2014 4.5.c Le modificateur « & » 10 "imul %%ebx" 11 :"=&a" (res) À moins qu’un opérande de sortie contienne « 12 :"0" (x), "r" (mult) & » dans sa contrainte, GCC peut le stocker dans 13 :"ebx"); le même registre alloué à un opérande d’entrée qui 14 15 printf("%d * %d = %d \n", x, mult, res) ne lui fait pas référence. C’est parce que le com- ; pilateur GCC suppose toujours que les instructions 16 return 0; assembleurfinissentl’utilisationdesopérandesd’en- 17 } trée avant que les sorties soient produites. Or, dans L’instruction imul utilise implicitement le registre certainscas,cettesuppositionestfausse,cequipeut EAX pour stocker le nombre à multiplier (comme provoquer des problèmes. Ainsi, le programme sui- entrée) et pour stocker le résultat de la multiplica- vant n’est pas fiable : tion. Ainsi, le premier opérande d’entrée est utilisé 1 __asm__("movl %1, %%eax\n\t" seulement avant la production de la sortie res. Voici 2 "addl %2, %%eax\n\t" un autre exemple montrant l’importance du modifi- 3 "subl %1, %1" cateur « & » dans quelques cas : 4 :"=a" (res) 5 :"r" (a), "b" (b)); 1 #include <stdio.h> Si le compilateur alloue le registre EAX au premier 2 3 int main(void) opérande d’entrée, le résultat de l’addition (contenu 4 { duregistreEAX)seramodifiéavantsonchargement 5 int x = 10; /* EAX */ dans res. C’est parce que la production de sortie 6 int divs = 3; res aura lieu juste après l’exécution de l’instruction 7 int quot; /* EAX */ 8 int reste; /* EDX */ subl!Voiciuneportionducode-cibleduprogramme 9 ci-dessus : 10 __asm__("subl %%edx, %%edx\n\t" 11 "movl %3, %%ebx\n\t" 1 movl $3, %edx 12 "idivl %%ebx" 2 movl $10, %eax 13 3 #APP 14 :"=a" (quot), "=&d" (reste) 4 # 9 "addition2.c" 1 15 :"0" (x), "r" (divs) 5 movl %eax, %eax 16 :"ebx"); 6 addl %edx, %eax 17 7 subl %eax, %eax 18 printf("%d / %d = %d \n", x, divs, quot 8 # 0 "" 2 ); 9 #NO_APP 19 printf("%d %% %d = %d \n", x, divs, Seule l’utilisation du modificateur « & », dans la reste); 20 return 0; contrainte de l’opérande de sortie, va prévenir l’al- 21 } location du registre EAX à l’opérande d’entrée. L’instruction idivl utilise implicitement le registre Dans l’exemple ci-dessus, l’utilisation de "0" EAX pour stocker le dividende (x) et le quotient comme contrainte du premier opérande d’entrée (quot). Le registre EDX sera utilisé implicitement n’est pas correcte. C’est parce qu’il est utilisé par pour stocker le reste (reste) de la division. Ainsi, l’instruction subl, en tant qu’opérande d’entrée, le registre EDX doit être indiqué dans la deuxième avantlaproductiondelasortieres.Parcontre,dans contrainte de sortie. l’exemple suivant, l’utilisation de la contrainte "0" Supposons qu’on n’ait pas utilisé l’identificateur est correcte : « & » dans la deuxième contrainte. Dans ce cas, le 1 #include <stdio.h> compilateur peut allouer le registre EDX pour sto- 2 cker le diviseur (divs). Et par conséquent, l’exécu- 3 int main(void) tion du programme peut provoquer une exception 4 { 5 int x = 10; /* EAX */ de type division par 0! 6 int mult = 3; Ainsi, lorsque le nom d’un registre est indiqué 7 int res; /* EAX */ comme contrainte de sortie, il vaut mieux d’utiliser 8 le modificateur « & ». 9 __asm__("movl %2, %%ebx\n\t" 5 Problèmes d’optimisation Durantl’optimisation,GCC tentederéordonner tructions,l’optimiseurconsidèrequelesinstructions et de réécrire le code du programme, même en pré- n’ontpasuneffetdeborddansleprogramme.Ainsi, sencedelaconstructionasm.Silesopérandesdesor- la construction asm peut être supprimée. Pour bien tienesontpasutilisés(lasection2deasm estvide), comprendreleproblème,onvaétudierlaportionde ou si leurs valeurs ne sont pas modifiées par les ins- code suivante, prise du fichier include/string.h du Developpez Magazine est une publication de developpez.com page 7 Numéro 52 Juin–Juillet 2014 code source du noyau Linux-0.01) : prime jamais un asm volatile. Mais il peut le dépla- cerdanslecode.Pouréviterça,vousdeveztoujours 1 extern inline char *strcpy(char *dest, const char *src) spécifier tout opérande modifié dans le code assem- 2 { bleur, comme opérande de sortie. Ainsi : 3 4 __asm__("cld\n" 1 extern inline char *strcpy(char *dest, 5 "1: lodsb\n\t" const char *src) 6 "stosb\n\t" 2 { 7 "testb %%al,%%al\n\t" 3 int S, D, A; 8 "jne 1b" 4 9 ::"S" (src), "D" (dest) 5 __asm__ __volatile__( 10 :"ax", "memory"); 6 "cld \n" 11 return dest; 7 "1:lodsb \n\t" 12 } 8 "stosb \n\t" La construction asm du code ci-dessus ne possède 9 "testb %%al, %%al \n\t" pas d’opérande de sortie. Pour le moment, on n’a 10 "jne 1b" 11 pas besoin d’utiliser de sortie puisque les instruc- 12 :"=&S (S)", "=&D (D)", "=&a (A) tionslodsb etstosb utilisentdirectementlamémoire. " Ainsi, on n’a pas de résultat à récupérer depuis un 13 :"0" (src),"1" (dest), "2" (0)) registre dans la mémoire à la fin de l’exécution du ; 14 return dest; bloc asm. Mais l’optimiseur est parfois fou! L’opti- 15 } misationrisqueradesupprimerlaconstructionasm. Et, par conséquent, la fonction strcpy() devient in- Dans l’exemple ci-dessus, le contenu des registres utilisable. ESI,EDI etEAX aétémodifié.Ainsi,onlesaspé- Vous pouvez empêcher la construction asm cifiés comme opérandes de sortie. Les variables S, d’être supprimée, par l’utilisation du mot-clé vola- D et A déclarées dans le code C sont utilisées juste tile, qui va indiquer au compilateur que les instruc- pour créer une dépendance avec le bloc asm. Ainsi, tions ont un effet de bord important. GCC ne sup- l’optimiseur ne déplacera pas ce dernier. 6 Utilisation des macros Si vous décidez d’utiliser des instructions assem- 18 bleur dépendantes de l’architecture, il vaut mieux 19 #endif pour vous les encapsuler dans des macros et les Notez que la dernière instruction d’une instruction placer dans un fichier d’en-tête. Cela peut vous ai- composée, écrite entre « », doit être une expres- der à la maintenance de vos programmes. Ainsi, si sion suivie par «; ». Elle sert à donner une valeur vousdécidezdeporterunprogrammeversuneautre à l’instruction entière. Dans notre exemple, on veut architecture, vous n’aurez besoin de réécrire qu’un récupérer la valeur de l’opérande de sortie dans le seul fichier. Dans l’exemple max.c, on a encapsulé codeC,pourl’afficherparexemple.Ainsi,onaécrit la construction asm dans la macro max(a,b) définie __res; à la fin de l’instruction composée. dans le fichier d’en-tête max.h : Dans la définition de la macro max(a,b), les va- 1 #ifndef MAX_H riables __x et __y sont utilisées pour s’assurer 2 #define MAX_H que la construction asm opère sur des valeurs en- 3 4 #define max(a,b) \ tières. Une autre méthode pour faire en sorte que 5 ({ \ la construction asm opère sur le type de données 6 int __res, __x = (a), __y = (b); \ correct est l’utilisation de forçage de type (casting) 7 __asm__ __volatile__( \ dans les entrées. Dans l’exemple ci-dessus, on peut 8 "cmpl %1, %2\n\t" \ 9 "jge 1f\n\t" \ forcer l’utilisation du type entier dans les opérandes 10 "movl %1, %0\n\t" \ d’entrée de la construction asm comme suit : 11 "jmp 2f\n\t" \ 12 "1: movl %2, %0\n\t" \ 1 (::"r" ((int)a), "r" ((int)b); 13 "2:" \ 14 :"=r" (__res) \ Pour le même objectif, les constructions asm 15 :"r" (__x), "r" (__y)); \ peuventêtreencapsuléesdansdesfonctionsenligne. 16 __res; \ La section suivante en donne un exemple. 17 }) Developpez Magazine est une publication de developpez.com page 8 Numéro 52 Juin–Juillet 2014 7 Un exemple détaillé 7.1 Opérations sur les chaînes de caractères 8 "1:\tlodsb\n\t" /* MOVB avec l’architecture x86 DS:ESI, AL */ 9 "stosb\n\t" /* MOVB Enbref,lesinstructionsx86 demanipulationdes AL, ES:EDI */ chaînes des caractères, comme lodsb et stosb, uti- 10 "testb\t%%al,%%al\n\t" /* ZF=1 si AL == 0 */ lisent implicitement les registres ESI et EDI. ESI 11 "jne\t1b" /* JMP doit contenir l’adresse, dans le segment DS, de la si ZF == 1 */ chaîne source, et EDI doit contenir celle, dans le 12 segment ES, de la chaîne de destination. Le registre 13 :"=&S" (S),"=&D" (D), "=&a" (A) 14 :"0" (src),"1" (dest), "2" (0) EAX est utilisé implicitement par ces instructions 15 :"memory"); pour stocker temporairement les données traitées. 16 } L’instruction cld va mettre à 0 le bit DF (Direc- Dans le code assembleur, on a utilisé l’instruction tion Flag) du registre EFLAGS. Ainsi, ESI et EDI cld. Donc, ESI et EDI doivent contenir les adresses seront incrémentés par le processeur durant l’exécu- src et dest du premier caractère de chaque chaîne. tion des instructions. A contrario, l’instruction std Enoutre,lesinstructionslodsb etstosb accèdent est utilisée pour mettre à 1 le bit DF, et ainsi ESI à la mémoire (src et dest) d’une manière impré- et EDI seront décrémentés. visible. En effet, on ne connaît pas à l’avance le Le programme string.c utilise les deux fonctions nombre d’octets (caractères) à copier. Donc, on a enlignemy_strcpy etmy_strcmp définiesdanslefi- utilisé "memory". chierstring.h.Lapremièrefonctionvainitialiserune D’autrepart,lestroisregistresESI,EDI etEAX chaînedecaractères;ladeuxièmevacomparerdeux serontmodifiésparlesinstructionsassembleur,donc chaînesinitialiséesetretourner0siellessontégales, on les a spécifiés comme opérandes de sortie. Ainsi, sinon elle retourne -1 ou 1. on doit utiliser le modificateur « & » pour prévenir l’allocation de ces registres à une entrée non cor- 1 #include <stdio.h> 2 #include <stdlib.h> recte. La connexion entre les entrées et les sorties 3 #include "string.h" aura lieu avec l’utilisation des contraintes "0", "1" 4 et "2". Cela est autorisé parce que les sorties S, D 5 int main (void) 6 { et A seront produites après la consommation des 7 char * str1 = (char*) entrées par les instructions. Elles sont utilisées juste 8 malloc(sizeof(char*)); pourcréerunedépendanceentrelecodeCetlebloc 9 char * str2 = (char*) asm! 10 malloc(sizeof(char*)); 11 L’utilisationdumotclévolatile etdesopérandes 12 my_strcpy("fooo", str1); de sortie va prévenir la suppression ou le déplace- 13 my_strcpy("foo", str2); mentdelaconstructionasm pendantl’optimisation. 14 15 if(my_strcmp(str1, str2)==0) 7.3 La fonction my_strcmp 16 printf("Les deux chaînes \"%s\" La fonction my_strcmp est aussi extraite du et \"%s\" "\ 17 "sont égales.\n", str1, str2); fichier include/string.h du code source du noyau 18 else Linux-0.01. Son fonctionnement est similaire à celui 19 printf("Les deux chaînes \"%s\" delafonctionstrcmp delabibliothèqueCstandard, et \"%s\" "\ 20 "ne sont pas égales.\n", str1, définie dans le fichier /usr/include/string.h. str2); 1 static inline int 21 2 my_strcmp(const char * str1,const char * 22 free (str1); str2) 23 free (str2); 3 { 24 return 0; 4 int S, D, __res; 25 } 5 6 __asm__ __volatile__( 7 "cld\n" /* ESI++, 7.2 La fonction my_strcpy EDI++ */ 8 "1:\tlodsb\n\t" /* MOV DS :ESI, AL */ 1 static inline void 9 "scasb\n\t" /* SUB ES 2 my_strcpy(char * src, char * dest) :ESI, AL */ 3 { 10 "jne 2f\n\t" /* JMP si 4 int S, D, A; ZF == 0 (ES:EDI != AL) */ 5 11 "testb %%al,%%al\n\t" /* ZF=1 6 __asm__ __volatile__ ( si AL == 0 */ 7 "cld\n\t" /* ESI++ 12 "jne 1b\n\t" /* JMP si , EDI++ */ ZF == 0 => il ya encore des Developpez Magazine est une publication de developpez.com page 9 Numéro 52 Juin–Juillet 2014 caractères */ 7.4 La compilation avec GCC 13 /* pour comparer Voici le makefile utilisé pour compiler le pro- */ gramme string.c : 14 "xorl %%eax,%%eax\n\t" /* (str1 == str2) => __res = 0 */ 1 CFLAGS = -O2 -fomit-frame-pointer -W - 15 "jmp 3f\n" /* on a Wall terminé ! */ 2 16 "2:\tmovl $1,%%eax\n\t" 3 string: string.o 17 "jl 3f\n\t" /* (str1 4 cc string.o -o string != str2) et (str1[i] > str2[ 5 i]) => __res = 1 */ 6 string.o: string.c string.h 18 "negl %%eax\n" /* (str1 7 cc -c $(CFLAGS) string.c -o != str2) et (str1[i] < str2[ string.o i]) => __res = -1 */ 8 19 "3:" 9 clean: 20 10 rm -rfv string.o 21 :"=&D" (S), "=&S" (S),"=&a" ( O2 est le niveau d’optimisation recommandé. Le __res) 22 :"0" (str1),"1" (str2), "2" (0) compilateur va essayer d’augmenter les perfor- 23 :"memory"); mances sans compromettre la taille et sans prendre 24 trop de temps en compilation. Ce niveau d’optimi- 25 return __res; sation permet de produire un code rapide. L’option 26 } -fomit-frame-pointer permet aussi de produire un coderapideetdetailleréduite.Consultezlemanuel de GCC pour avoir accès à encore plus d’informa- tions. Retrouvez l’article d’Issam Abdallah en ligne : lien 5 Developpez Magazine est une publication de developpez.com page 10 Numéro 52 Juin–Juillet 2014

Description:
script) et signale les erreurs/avertissements sur la marge de l'éditeur. Un survol de souris permet d'ob- tenir plus de détails sur la nature de l'erreur ou.
See more

The list of books you might like

Most books are stored in the elastic cloud where traffic is expensive. For this reason, we have a limit on daily download.