Vous êtes sur la page 1sur 38

Utilisation de l'assembleur en ligne avec Delphi

par Nono40

Date de publication : 11/09/2003 Dernire mise jour : 11/09/2003

Ce document prsente l'utilisation de l'assembleur en ligne intgr dans Delphi. Il dcrit en dtail l'utilisation en assembleur des principaux type de donnes utiliss en pascal. La version "en ligne" de ce document est ici :

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Introduction I - Programmer en assembleur sous Delphi I-A - Inclure du code assembleur I-B - Quelles sont les instructions utilisables ? I-C - Quels sont les registres utilisables ? I-D - Sur quoi pointent les registres segments ? I-E - Ecrire le code I-E-1 - Oprandes I-E-2 - Labels I-E-3 - Directives I-E-4 - Oprateurs spciaux I-E-5 - Commentaires II - Accs aux diffrents types de donnes II-A - Gnralits II-B - Types ordinaux II-C - Types ensembles II-D - Types rels II-E - Type Int64 II-F - Tableaux statiques II-G - Chanes courtes II-H - Enregistrements III - Ecrire une fonction en assembleur III-A - Gnralits III-B - Code d'entre et de sortie III-C - Empilage des paramtres III-D - Conventions d'appel III-D-1 - Gnralits III-D-2 - Convention de type Pascal. III-D-3 - Convention de type StdCall III-D-4 - Convention de type C. III-D-5 - Convention de type Register. III-E - Paramtres et rsultat de la fonction III-E-1 - Types ordinaux III-E-2 - Types ensembles III-E-3 - Types rels III-E-4 - Type Int64 III-E-5 - Tableaux statiques III-E-6 - Chanes courtes III-E-7 - Enregistrements IV - Accder aux objets IV-A - Appel d'une mthode statique IV-B - Appel d'une mthode virtuelle
-2Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

IV-C - Appel d'une mthode dynamique IV-D - Appel d'une mthode de classe IV-E - Accs aux proprits V - Cration d'un objet. V-A - Le constructeur V-B - Le destructeur V-C - Ecriture des mthodes. V-D - Ecriture d'une mthode de classe. VI - Problmes spcifiques l'assembleur VI-A - Fonction SizeOf() VI-B - Erreur de codage due OFFSET VI-C - Erreur due un EBP implicite VI-D - Erreur d'adresse dans des sous-procdures Conclusion

-3Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Introduction
Ce document est destin tous ceux qui souhaitent utiliser de l'assembleur dans Delphi. Ceci peut dans certains cas tre plus rapide que l'criture en langage volu. Ce document n'est pas un cours d'initiation l'assembleur, il suppose que vous connaissiez la structure des registres et le langage des processeurs x86 et compatibles. De mme il est suppos que vous avez une bonne connaissance du pascal. Il n'est pas ncessaire d'avoir des notions prcises des modes Rel, Protg et Virtuel du 386, ni de la structure segmente de la mmoire propre aux processeurs x86. Ce document ne prsente pas non plus de mthode d'optimisation grce l'assembleur. Mais plutt une description dtaille de l'interfaage de l'assembleur avec le pascal. Vu l'poque actuelle, et le peu de systmes 16 bits encore en service, tout ce document ne porte que sur Delphi 2 et suivant. C'est--dire sur l'adressage 32 bits des processeurs. L'utilisation de fonctions rcentes (SSE2) requiert Delphi 6.

-4Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

I - Programmer en assembleur sous Delphi I-A - Inclure du code assembleur


Pour intgrer de l'assembleur dans le code Pascal de Delphi, il suffit de l'entourer des mots clefs Asm et End. Toutes les instructions situes entre ces mots doivent tre des instructions assembleur. Elles sont insres tel que dans le code excutable. Exemple simple :
procedure TForm1.Button2Click(Sender: TObject); Var a,b:Integer; begin A:=1; B:=2; Asm Mov EAX,A Add B,EAX End; Label1.Caption:=IntToStr(b); end;

I-B - Quelles sont les instructions utilisables ?


Delphi7 intgre dans l'assembleur en ligne tout le jeu d'instructions dfini par Intel. Que ce soient les instructions de base, FPU, MMX, SSE et SSE2. (Bien sr toutes ne sont pas utilisables suivant les processeurs !) Delphi est en mode d'adressage 32bits, c'est--dire qu'il vaut mieux utiliser les registres 32 bits par dfaut. Il est toutefois possible de travailler avec les registres 8 et 16 bits, Delphi ajoutant les prfixes ncessaires pour les oprations. De mme l'adressage tendu est utilis par dfaut, c'est--dire que les adressages suivants sont autoriss :
Mov EAX,BaseTableau[ECX+EDX*4] Mov EAX,Dword ptr [ESI+EDI+20]

I-C - Quels sont les registres utilisables ?


Tous les registres dfinis dans la structure IA32 des processeurs Intel sont utilisables : Registres communs : EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP ainsi que les registres AX,BX,CX,DX,SI,DI,BP,SP,AL,AH,BL,BH,CL,CH,DL,DH Registre d'tat EFLAGS Registres de segment : DS ES FS GS CS SS, bien sur il est rare d'avoir utiliser ses registres dans Delphi. Ce n'est recommand qu'aux utilisateurs avancs, et inutile dans la plupart des cas. ( voir plus bas ) Registres FPU : ST0 ST7 Registres MMX : MM0 MM7 Registres SSE/SSE2 : XMM0 XMM7 et MXCSR

-5Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Tous les registres sont utilisables dans le code assembleur, par contre vous ne devez pas modifier le contenu des registres suivants : EBX, ESI, EDI, EBP, ESP, DS, ES, CS et SS. En cas de besoin il faut en sauvegarder leur valeur en dbut de code et la restituer en fin :
PUSH EBX PUSH EDI // Code asm utilisant EBX et EDI POP EDI POP EBX

I-D - Sur quoi pointent les registres segments ?


Les registres de segments sont chargs par Delphi. Il n'est pas utile de modifier leur valeur. Delphi fonctionne en mode protg en adressage 32 bits. Toute la mmoire de l'application est donc visible sans avoir changer la valeur des segments. DS et ES pointent sur la zone donnes de l'application, que ce soient des variables statiques ou des objets. Les instructions de chanes utilisant ces segments par dfaut, il n'est pas utile de surcharger avec les prfixes ES : ou DS : vu que les deux pointent sur la mme plage d'adresses SS pointe sur la mmoire de la pile. Dans une application Delphi SS contient le mme descripteur que ES/DS. CS pointe sur le code, sa valeur doit tre utilise pour l'accs au code. Notez que dans 99% des cas, la gestion des segments effectue par Delphi est suffisante et il n'est pas utile de se poser la question du contenu de ces registres.

I-E - Ecrire le code


La syntaxe d'une instruction assembleur est la suivante :
[Label :] Instruction Oprande1[,Oprande2[,Oprande3]

Le nombre d'oprande doit correspondre avec l'instruction utilise. Quand diffrents nombres d'oprandes sont utilisables pour une mme instruction, Delphi encode l'instruction correspondant au nombre d'oprandes utilises. C'est le cas notamment pour l'instruction IMUL.

I-E-1 - Oprandes
Les oprandes possibles sont les suivantes. Les combinaisons autorises dpendent de l'instruction utilise. Valeur immdiate Registre commun ou spcifique Variables Delphi Adresse mmoire directe ou indexe

-6Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Pour les valeurs immdiates, les rgles d'valuation la compilation sont les mmes que pour le pascal. Les valeurs suivantes sont autorises :
Const Valeur=123 ; ... MOV EAX,4 MOV ECX,Valeur MOV ECX,(Valeur+2)*3

Une valeur immdiate sera toujours de la mme taille que le registre/mmoire de destination dans la mesure o Delphi est capable d'en valuer la taille. Dans le cas contraire il faut forcer la taille de l'opration en utilisant l'une des directives BYTE PTR, WORD PTR etc.
MOV BYTE PTR [EDI],3

La taille des oprandes doit correspondre l'instruction utilise et les tailles des oprandes doivent correspondre entre elles. Delphi ne vrifie que la taille en octets des oprandes et non pas son type exact. Pas exemple les types Integer, Dword et Array[0..3] of byte sont identiques au niveau de l'assembleur. Exemples de concordance de taille d'oprande :
Var a:Integer; b:Word; C:Array[0..3]Of Byte; R8:Array[0..7]Of Byte; R16:Array[0..15]Of Byte; R:Record rI:Integer; rD:Integer; End; begin Asm MOV EAX,EBX MOV EAX,A MOV CX,B MOV EAX,C MOV EAX,R.rD MOVQ MM1,R8 MOVDQU XMM1,R16 end; end;

Attention c'est le type de variable directement qui est utilis pour la concordance. Dans le cas d'un tableau, c'est la taille du type complet mme si on accde un indice, car l'indice n'est pas interprt comme indice du tableau, mais comme un Offset supplmentaire ajout l'adresse de base du tableau.
Var T4:Array[0..10]Of Integer; Begin Asm MOV EAX,T4[2] // Incorrect End; End;

-7Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Dans le cas d'un adressage indirect, ou dans le cas d'un transtypage il est possible de forcer la taille de l'oprande l'aide d'une des directives suivantes :
Var Buff:Array[0..511]Of Byte; begin Asm MOV AL,Byte ptr Buff // 1 octet MOV AX,Word ptr Buff // 2 octets MOV EAX,DWord ptr Buff // 4 octets MOVQ MM0,QWord ptr Buff // 8 octets MOVDQU XMM1,DQWord ptr Buff // 16 octets FLD FLD end; end; QWord ptr Buff TByte ptr Buff // 8 octets // 10 octets

I-E-2 - Labels
Les labels sont dfinis comme en pascal l'aide du mot clef label :
Label Retour ; # Asm Retour: ADD EAX,Tableau[ECX*4] LOOP Retour End;

Il est possible d'utiliser un label commenant par @, dans ce cas il n'est pas ncessaire de le dfinir dans une clause label. Mais il n'est alors utilisable que dans le mme bloc ASM.
Asm JMP @LAB1 // Correct JMP @LAB2 // Interdit # @LAB1: ADD EAX,EDX End Inc(UneVariable) ; Asm @LAB2: ADD EAX,ECX End;

I-E-3 - Directives
Les directives suivantes sont utilisables dans le code assembleur : DB,DW,DD,DQ : Insertion en ligne de donnes de type byte, word, dword ou quadword Exemples :
DB 1 DB 'A' DD 12345678 DQ $ABCDEFGH12345678

-8Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Ces directives intgrent directement les valeurs dans le code l'endroit o elles sont donnes. Il est prfrable d'utiliser des constantes dans une zone const pour dfinir ce genre de valeur. La directive DB permet aussi d'inclure du code machine " inline ", cette mthode est dconseille mais peut servir dans certains cas particuliers. Les directives VMTOFFSET et DMTINDEX permettent d'accder aux mthodes virtuelles et dynamiques des objets. ( voir le chapitre sur les objets )

I-E-4 - Oprateurs spciaux


Les oprateurs suivants peuvent tre utiliss sur les oprandes : Low : retourne l'octet de poids faible de l'oprande. Ne pas confondre avec la fonction Low() du pascal. High : retourne l'octet de poids fort de l'oprande. Ne pas confondre avec la fonction High() du pascal. Type : Retourne la taille en octet de l'oprande. C'est l'quivalent de la fonction SizeOf() du pascal. : : Oprateur de surcharge du segment par dfaut d'une instruction. [ ] : Offset ajout l'adressage en cours, il peut contenir des registre, un identificateur ou une valeur immdiate. L'offset ajout est toujours calcul en octets.

I-E-5 - Commentaires
L'ajout de commentaires dans le code assembleur est effectu par les mmes balises qu'en pascal. De plus ceux-ci ne peuvent tre placs en milieu de ligne. Le commentaire assembleur de fin de ligne ';' n'est pas reconnu, il doit tre remplac par //. Remarque : l'assembleur tant moins lisible que le pascal, il est fortement conseill de bien commenter le code.

-9Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

II - Accs aux diffrents types de donnes II-A - Gnralits


Tous les types de donnes peuvent tre utiliss en assembleur. Cependant tous les types statiques sont beaucoup plus simples utiliser. Les sections suivantes donnent en dtail l'utilisation de ces principaux types. Les types dynamiques comme String ou Array Of -type-, sont d'un usage plus compliqu et ncessitent l'usage de fonctions internes Delphi non documentes. Ils ne seront donc pas dcrits ici. Dans la plupart des cas l'utilisation des types de donnes peut tre fait sans utilisation de la directive xxx PTR. L'erreur de compilation " Non concordance de taille d'oprande " signale le plus souvent une erreur dans le choix d'un registre ou la taille d'une mmoire.

II-B - Types ordinaux


Les ordinaux sont tous les types quivalents une valeur entire. C'est--dire les types entiers, numrs, boolens, caractres ou pointeurs. L'utilisation de ces types est simple, l'assembleur travaille toujours sur leur reprsentation entire.
Type TMonEnum=(Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche); Var A,F:Integer; B:Byte; C:Char; D:Word; Enum:TMonEnum; begin Asm MOV EAX,A ADD EAX,F MOV AL,B MOV CL,C MOV AL,Enum; CMP AL,Vendredi end; end;

Attention le type numr est quivalent Byte, Word ou Dword suivant la valeur la plus grande qu'il contient.
Type TEnumByte=(Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche); TEnumWord=(Zero,Mille=1000,DeuxMille=2000,TroisMille=3000); TEnumDWord=(A,B=100000,C=200000); Var EnumB:TEnumByte; EnumW:TEnumWord; EnumD:TEnumDWord;

- 10 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

begin Asm MOV CMP MOV CMP MOV CMP end; end;

AL,EnumB; // byte AL,Vendredi AX,EnumW; // word AX,DeuxMille EAX,EnumD; // DWord EAX,C

II-C - Types ensembles


Les ensembles sont reprsents en mmoire par une suite de bits donc chaque bit donne l'appartenance de l'lment l'ensemble. Le nombre d'octets utiliss dpend du nombre maximum d'lments de l'ensemble. Ce nombre peut aller de 1 32 octets (de 1 256 lments). Les petits ensembles (moins de 32 valeurs ) peuvent tre manipuls directement. En exemple un ensemble de 7 valeurs (stock sur un type byte, car moins de 8 valeurs )
Type TJour =(Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche); TEnsCourt=Set Of TJour; Var LesJours1:TEnsCourt; LesJours2:TEnsCourt; begin Asm MOV AL,LesJours1 OR AL,LesJours2 end; End;

De mme les ensembles de 9 16 valeurs sont utilisables comme un type Word, les ensembles de 17 32 valeurs sont utilisables comme un type DWord. Pour 33 valeurs et plus, il n'y a plus de correspondance directe. Leur manipulation doit tre effectue en plusieurs tapes avec un transtypage :
Type TListe = 0..63; TEnsLong =Set Of TListe;// Ensemble de 64 valeurs Var EnsLong1:TEnsLong; EnsLong2:TEnsLong; begin Asm MOV EAX,DWord ptr EnsLong1 OR EAX,DWord ptr EnsLong2 MOV EAX,DWord ptr EnsLong1[4] OR EAX,DWord ptr EnsLong2[4] end; end;

II-D - Types rels

- 11 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Les types rels sont Single, Double, Extended, Comp et Currency. Ces types sont utiliss de faon native par l'unit de calcul flottant intgre aux processeurs. Il est fortement conseill de manipuler ces donnes avec le FPU. L'change de ces types avec les registres FPU est direct :
Var S1,S2:Single; D1,D2:Double; E1,E2:Extended; C1,C2:Currency; begin Asm FLD S1 // Single FADD S2 WAIT FST S1 FLD D1 // Double FADD D2 WAIT FST D1 FLD E1 // Extended FLD E2 FADD WAIT FSTP E1 FLD C1 // Currency FLD C2 FADD C2 WAIT FST C1 end; end;

Note : le type Real48 n'est pas dcrit ici. C'est un type rel non natif prsent simplement pour la compatibilit avec les programmes antrieurs Delphi.

II-E - Type Int64


Le type Int64 ne peut tre trait directement par les registres communs ou les oprations mmoires classiques. Dans la plupart des cas le transtypage en deux Dword est utilis.
Var A:Int64; B:Int64; begin Asm // A:=A+B MOV EAX,DWord ptr B ADD DWord ptr A,EAX MOV EAX,DWord ptr B[4] ADC DWord ptr A[4],EAX end; end;

Certaines instructions FPU utilisent des valeurs entires sur 64 bits, dans ce cas le type Int64 est utilis directement :

- 12 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Var A:Int64; D:Double; begin Asm // D:=D+A FLD D // Valeur flottante FILD A // Valeur entire FADDP WAIT FST D end; end;

Le type Int64 est aussi compatible avec les instructions MMX ou SSE portant sur des entiers 64 bits :
Var A:Int64; B:Int64; begin Asm // A:=A+B MOVQ MM0,A PADDQ MM0,B MOVQ A,MM0 end; end;

II-F - Tableaux statiques


Les tableaux sont considrs comme un type dont la longueur est la taille totale du tableau. Pour accder un seul lment du tableau, le transtypage est systmatique. Le premier lment du tableau est toujours avec un dcalage nul par rapport l'adresse de base du tableau. Par exemple les deux tableaux suivants sont stocks de la mme manire en mmoire :
Var Tab1 :Array[0..3]Of Integer ; Tab2 :Array[2..5]Of Integer ;

Attention, l'oprateur [ ] ne signifie pas indice du tableau mais Offset supplmentaire. Pour accder au deuxime lment de Tab1 il faut crire Tab1[4]. Dans le cas d'un parcourt du tableau l'aide d'un index, il faut augmenter l'index chaque boucle de la taille de l'lment de base du tableau. Il est conseill d'utiliser l'oprateur Type.
Var Tab1 :Array[1..20]Of Integer; Somme:Integer; begin Asm XOR ECX,ECX XOR EAX,EAX @L1:ADD EAX,DWord Ptr Tab1[ECX] ADD ECX,Type Integer CMP ECX,Type Tab1 JB @L1 MOV Somme,EAX end; end;

- 13 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Il faut penser aussi aux multiplicateurs lors de l'adressage. Ceci peut simplifier les oprations sur des tableaux dont le type de base est de taille 2,4 ou 8 octets. Exemple d'optimisation de la boucle, en utilisant un coefficient multiplicateur d'index :
Var Tab1 :Array[1..20]Of Integer; Somme:Integer; begin Asm // Nombre d'lment du tableau MOV ECX,(Type Tab1)/(Type Integer) XOR EAX,EAX // -4 Car ECX va Balayer de 20 1 au lieu de // 19 0 @L1:ADD EAX,DWord Ptr Tab1[ECX*4-Type Integer] LOOP @L1 MOV Somme,EAX end; end;

Les types tableaux peuvent aussi servir d'oprande dans les oprations MMX/SSE dans le cas d'oprations groupes. Par exemple dans le cas d'instructions MMX sur des groupes les types suivants peuvent tre utiliss directement :
Var TabB1,TabB2 :Array[0..7]Of Byte; TabW1,TabW2 :Array[0..3]Of Word; TabD1,TabD2 :Array[0..1]Of Integer; begin Asm // addition des lments de TabB2 TabB1 MOVQ MM0,TabB1 PADDB MM0,TabB2 MOVQ TabB1,MM0 // addition des lments de TabW2 TabW1 MOVQ MM0,TabW1 PADDW MM0,TabW2 MOVQ TabW1,MM0 // addition des lments de TabD2 TabD1 MOVQ MM0,TabD1 PADDD MM0,TabD2 MOVQ TabD1,MM0 end; end;

II-G - Chanes courtes


Les chanes courtes sont un tableau d'octets dont l'indice 0 donne la taille de la chane. Leur utilisation est identique celle des tableaux, avec en plus la gestion de l'indice 0 comme longueur. Les instructions de chane sont adaptes au traitement de ce type de donne.
Var Chaine:ShortString; begin Asm // Chaine:='AAAAAAAA'

- 14 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

PUSH EDI // Obtention de l'adresse du premier caractre LEA EDI,CHAINE[1] MOV ECX,8 MOV AL,'A' // Stockage des huit 'A' REP STOSB // Mise jour de la longueur de la chane MOV Byte Ptr Chaine[0],8 POP EDI end; end;

II-H - Enregistrements
L'assembleur intgr inclus aussi l'oprateur . identique celui du pascal pour obtenir un membre d'un enregistrement. La concordance de taille est alors effectue sur le membre en question et non le type global. Cela simplifie l'utilisation des enregistrements en assembleur l'offset de chaque membre tant ajout par le compilateur.
Var Rect:TPoint; begin Asm MOV EAX,RECT.X MOV ECX,RECT.Y end; end;

Dans l'exemple ci-dessus, le compilateur va ajouter les offsets ncessaires pour atteindre les membres X et Y ( +0 pour X et +4 pour Y dans ce cas ) Le transtypage d'une adresse en variable de type enregistrement est aussi possible. C'est trs utile dans le cas d'utilisation d'un index seul ou d'un tableau d'enregistrements.
Var TabRect:Array[0..9]Of TPoint; SommeX:Integer; SommeY:Integer; begin Asm XOR ECX,ECX XOR EAX,EAX XOR EDX,EDX @L1:ADD EAX,TabRect[ECX].TPoint.X ADD EDX,TabRect[ECX].TPoint.Y ADD ECX,Type TPoint CMP ECX,Type TabRect JB @L1 MOV SommeX,EAX MOV SommeY,EDX end; end;

- 15 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

III - Ecrire une fonction en assembleur III-A - Gnralits


L'criture d'une fonction ou d'une procdure en assembleur est effectue en supprimant le begin de dbut de code et en le remplaant par asm. Tout le code de la fonction doit tre crit en assembleur.
Function Somme(A,B :Integer) :Integer; Asm ADD EAX,ADX End;

Le fait de supprimer le begin, supprime toutes les copies de paramtres passs par valeur dont la taille est suprieure 4 octets. Il faut considrer que le passage de tels paramtres est implicitement fait avec la directive var. ( voir III-E pour plus de dtail en fonction des types de paramtres ) Note : le mot-clef Assembler n'existe que par soucis de compatibilit et ne doit pas tre utilis. De mme le mot-clef Interrupt permettant l'criture d'une procdure d'interruption n'existe plus depuis Delphi2.

III-B - Code d'entre et de sortie


Lors de l'criture d'une fonction en assembleur, Delphi gre automatiquement le cadre de pile pour l'accs aux paramtres et la gestion des variables locales. Ce cadre est optimis en fonction des besoins, seules les instructions indispensables sont ajoutes au code. L'entre de la procdure ( Asm ) est code par :
PUSH EBP // seulement si la pile contient des paramtres# MOV EBP,ESP // # ou s'il existe des variables locales SUB ESP,XXX // Seulement dans le cas de variables locales

La sortie de la procdure ( End ) est code par :


POP EBP // seulement si la pile contient des paramtres# // # ou s'il existe des variables locales RET YYY // Cod dans tous les cas

Dans le cas o il n'y a pas de paramtres dans la pile ou dans le cas de la convention Cdecl, une simple instruction RET est gnre. Dans tous les cas le RET gnr est un RET Near. Du code supplmentaire est ajout ventuellement est dbut et fin de fonction dans le cas d'utilisation de variables dynamiques comme les types String et Array Of -type-, ainsi que dans les constructeurs/destructeurs de classes.

- 16 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

III-C - Empilage des paramtres


L'empilage des paramtres est toujours effectu par mot entier (4 octets). Si le paramtre empiler est plus petit qu'un entier, il faut tout de mme empiler 4 octets. Par exemple pour empiler la variable B de type byte il faut faire comme suit :
MOV AL,B // Chargement de B PUSH EAX // Empilage d'un entier dans tous les cas

Dans le cas de paramtres empils par valeur dans la pile mais dont la taille est suprieure quatre octets, il faut commencer par empiler le poids fort. En effet, la pile tant construite en descendant, le poids fort sera en adresse la plus haute et le poids faible en adresse la plus basse. Exemple pour V de type Int64 :
PUSH DWord ptr V[4] PUSH DWord ptr V

III-D - Conventions d'appel


Il me semble utile de rappeler la signification des conventions de passage des paramtres. C'est trs utile pour l'criture de fonctions, mais surtout pour l'appel de fonctions, crites en assembleur ou non.

III-D-1 - Gnralits
Toutes les fonctions utilisent la pile processeur pour le passage des paramtres. Cette pile est aussi utilise pour la rservation de l'espace des variables locales la fonction. L'ordre de passage dans la pile dpend de la convention utilise. A la fin de la fonction, les paramtres et les variables locales sont supprimes de la pile et l'excution du programme reprend l'instruction suivant l'appel. La mthode de suppression des paramtres dpend aussi de la convention utilise. L'accs aux paramtres est effectu par le registre EBP. ESP n'est pas utilis car il est automatiquement modifi par les instruction POP et PUSH, rendant inaccessibles les paramtres et variables locales. EBP est donc un registre trs particulier dans les langages volus. Il doit tre sauvegard ds le dbut de la fonction. Cette sauvegarde est automatiquement effectue par Delphi l'entre de la fonction. L'instruction Begin ou Asm de dbut d'une fonction ajoute les lignes PUSH EBP et MOV ESP,EBP au code.
Procedure UneFonction(Param1,Param2 :Integer) ;Pascal ; Var Entier1 :Integer; Real1 : Double; Asm // code End;

- 17 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Au dbut du code utile de la fonction, l'aspect de la pile est le suivant :


XXXXXX EBP+12 : Param1 : Paramtre de la fonction EBP+8 : Param2 : Paramtre de la fonction EBP+4 : [EIP] : Adresse de retour de la fonction EBP> : [EBP] : Sauvegarde de EBP EBP-4 : Entier1 : Variable locale de type integer EBP-12 : Real1 : Variable locale de type double.

Le paramtre 1 sera alors accessible avec [EBP+12] La variable locale Entier1 sera accessible avec [EBP-4] Important : il conseill d'utiliser les identificateurs des paramtres au lieu de leur quivalent utilisant EBP, ceci rend la modification de la taille des variables et de leur place automatiques. Par exemple MOV EAX,Param1 est prfrable MOV EAX,[EBP+12] Les paragraphes suivants dcrivent toutes les conventions, en prenant pour exemple une fonction simple :
Function Diff(A,B :Integer) :Integer ; Begin Result :=A-B; End;

Le codage correspondant en assembleur sera donn pour chaque cas

III-D-2 - Convention de type Pascal.


C'est la convention par dfaut dans Delphi hors optimisations. Les paramtres sont empils dans l'ordre de la fonction. La suppression des paramtres est la charge de la fonction.
Function Diff(A,B :Integer) :Integer ;Pascal ; Asm Mov EAX,A // A est ici [EBP+12] Sub EAX,B // B est ici [EBP+ 8] End;

Avant l'appel :
ESP > : XXXXXX

Aprs l'appel (juste avant l'excution de la ligne Result :=)


: XXXXXX EBP+12 : A : Paramtre de la fonction EBP+8 : B : Paramtre de la fonction EBP+4 : [EIP] : Adresse de retour de la fonction ESP/EBP>: [EBP] : Sauvegarde de EBP

- 18 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Aprs l'excution du End de la fonction


ESP > : XXXXXX

Le code gnr par le Begin (ou Asm ) est le suivant :


PUSH EBP MOV EBP,ESP

Le code gnr par le End est le suivant :


POP EBP RET 8

On remarque que le RET 8 permet de supprimer les paramtres de la pile la fin de la fonction.

III-D-3 - Convention de type StdCall


C'est la convention par dfaut des fonctions Windows et des dlls. Les paramtres sont empils dans l'ordre inverse de la fonction. La suppression des paramtres est la charge de la fonction.
Function Diff(A,B :Integer):Integer;StdCall; Asm Mov EAX,A // A est ici [EBP+ 8] Sub EAX,B // B est ici [EBP+12] End;

Avant l'appel :
ESP > : XXXXXX

Aprs l'appel (juste avant l'excution de la ligne Result :=)


ESP > : XXXXXX : EBP+12 : B : Paramtre de la fonction EBP+8 : A : Paramtre de la fonction EBP+4 : [EIP] : Adresse de retour de la fonction ESP/EBP>: [EBP] : Sauvegarde de EBP

Aprs l'excution du End de la fonction


ESP > : XXXXXX

Le code gnr par le Begin (ou Asm ) est le suivant :


PUSH EBP MOV EBP,ESP

- 19 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Le code gnr par le End est le suivant :


POP EBP RET 8

On remarque que le RET 8 permet de supprimer les paramtres de la pile la fin de la fonction.

III-D-4 - Convention de type C.


C'est la convention par dfaut des fonctions crites en C. Les paramtres sont empils dans l'ordre inverse de la fonction. La suppression des paramtres est la charge du programme appelant.
Function Diff(A,B :Integer):Integer;Cdecl; Asm Mov EAX,A // A est ici [EBP+ 8] Sub EAX,B // B est ici [EBP+12] End;

Avant l'appel :
ESP > : XXXXXX

Aprs l'appel (juste avant l'excution de la ligne Result :=)


: XXXXXX : EBP+12 : B : Paramtre de la fonction EBP+8 : A : Paramtre de la fonction EBP+4 : [EIP] : Adresse de retour de la fonction ESP/EBP>: [EBP] : Sauvegarde de EBP

Aprs l'excution du End de la fonction


: XXXXXX : :B : Paramtre non dpil ESP > : A : Paramtre non dpil

Le code gnr par le Begin (ou Asm ) est le suivant :


PUSH EBP MOV EBP,ESP

Le code gnr par le End est le suivant :


POP EBP RET

Attention, dans ce cas c'est un simple RET qui est effectu, il faut penser librer les paramtres soi-mme (ici avec un ADD ESP,8) aprs l'appel de la fonction.

- 20 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

III-D-5 - Convention de type Register.


C'est la convention par dfaut dans Delphi avec les optimisations. Les paramtres sont stocks dans la mesure du possible dans les registres. Les registres utiliss sont dans l'ordre EAX EDX et ECX. Si la fonction dispose de plus de trois paramtres, ils sont placs dans la pile comme pour la convention de type Pascal. De mme les types rels ou int64 sont placs dans la pile. Les chanes, les types structurs et les ensembles longs peuvent tre en paramtre registre car ce sont des pointeurs vers un bloc du type correspondant. Si il n'y a pas de paramtres dans la pile et pas de variables locales, EBP n'est pas sauvegard.
Function Diff(A,B :Integer):Integer;Register; Asm SUB EAX,EDX // A est ici EAX et B est EDX End;

Avant l'appel :
ESP > : XXXXXX :

Aprs l'appel (juste avant l'excution de la ligne Result :=)


: XXXXXX : ESP > :[EIP] : Adresse de retour

Aprs l'excution du End de la fonction


ESP > : XXXXXX :

Dans ce cas il n'y a pas de code gnr par Begin, car les deux paramtres sont placs dans EAX et EDX Le code gnr par le End est le suivant :
RET

III-E - Paramtres et rsultat de la fonction


Quelle que soit la convention d'appel, le rsultat d'une fonction est retourn de la mme manire. Mais suivant le type de paramtre ou de rsultat le codage est diffrent. Dans la suite nous allons dcrire le codage d'une fonction " Somme " d'un certain nombre de types de paramtres, en retournant le rsultat correspondant. De plus un appel de cette fonction en assembleur sera galement effectu afin de bien montrer dans chaque cas le code prparatoire l'appel.

- 21 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

La convention utilise ici est Register, Dans le cas des autres conventions la transformation des paramtres est la mme. La diffrence est que les valeurs ordinales, ou assimilables des valeurs ordinales, sont passs dans la pile. Il est conseill de mettre en tte de fonction comment sont passs les paramtres et comment le rsultat est retourn. Cela facilite la maintenance des fonctions en assembleur. Bien sr il est possible de passer les paramtres sans respecter les normes. Mais ceci implique que la fonction et l'appel de la fonction soient crits en assembleur. Delphi n'interprte jamais le passage des paramtres en fonction du code. Je conseille donc vivement de conserver le passage normal des paramtres.

III-E-1 - Types ordinaux


Tous les types ordinaux, ainsi que les ensembles courts et les pointeurs. Le rsultat est retourn dans AL pour tous les types occupant un octet. Dans AX pour les types occupant deux octets et dans EAX pour les types occupant 4 octets. Fonction :
Function SommeInteger(A,B:Integer):Integer; // A est dans EAX // B est dans EDX // Resultat dans EAX Asm ADD EAX,EDX end;

Appel :
Procedure AppelSomme; Var v:Integer; Begin Asm // V:=V+4 MOV EAX,V MOV EDX,4 CALL SommeInteger MOV V,EAX End; End;

III-E-2 - Types ensembles


Pour les ensembles courts (de 1 32 valeurs) le rsultat est retourn dans AL, AX ou EAX suivant la taille de l'ensemble. Pour les ensembles longs (33 256 valeurs), c'est le programme appelant qui doit rserver une zone mmoire pour le rsultat de la fonction puis passer l'adresse de cette zone en tant que paramtre pointeur.

- 22 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Fonction :
Type TListe = 0..63; // Dfinition d'un type ensemble plus grand qu'un entier (sur 64 bits ici) TEnsLong=Set Of TListe; Function SommeSetLong(Ens1,Ens2:TEnsLong):TEnsLong;Register; // EAX : Adresse de Ens1 // EDX : Adresse de Ens2 // Resultat dans [ECX] Asm PUSH EBX MOV EBX,[EAX] OR EBX,[EDX] MOV [ECX],EBX MOV EBX,[EAX+4] OR EBX,[EDX+4] MOV [ECX+4],EBX POP EBX End;

Important : l'emplacement du rsultat de la fonction est rserv par l'appelant, celui-ci donnant un pointeur vers la zone rserve en tant que paramtre supplmentaire. ECX va donc contenir ici l'adresse de stockage du rsultat. Appel :
Procedure AppelSommeSetLongAsm; // Les constantes Types pour les paramtres constants // sont le plus simple Const CE1:TEnsLong=[0,2,4,6]; CE2:TEnsLong=[4,20,63]; Var E2:TEnsLong; Asm LEA EAX,CE1 // Premier ensemble LEA EDX,CE2 // Deuxime ensemble LEA ECX,E2 // Adresse ou stocker le rsultat CALL SommeSetLong End;

Dans le code ci-dessus, remarquez l'utilisation des constantes types pour les enregistrements constants. De mme, le fait de dclarer une variable locale E2 permet de rserver la place pour le rsultat de la fonction.

III-E-3 - Types rels


Les paramtres rels sont passs par valeur dans la pile, bien que leur taille soit suprieure 4 octets. Les rsultats rels sont retourns dans le registre du haut de la pile du coprocesseur. Attention, c'est au code appelant de dpiler le rsultat : Fonction :

- 23 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Function SommeDouble(A,B:Double):Double; // [EBP+$10] contient A ( sur 8 octets ) // [EBP+$08] contient B ( sur 8 octets ) // ST0 contiendra le rsultat Asm FLD A FADD B WAIT End;

Appel :
Procedure AppelSommeDouble; Var A,R:Double; Const B:Double=2.3; Begin A:=1; Asm // R :=A+B PUSH DWORD PTR A[4] // Un double est sur 8 octets PUSH DWORD PTR A PUSH DWORD PTR B[4] // Un double est sur 8 octets PUSH DWORD PTR B CALL SommeDouble FSTP R // Dpilage + Stockage du rsultat // R :=A+2.3 PUSH DWORD PTR A[4] // Un double est sur 8 octets PUSH DWORD PTR A PUSH $40026666 // Ici la constante relle ( 2.3 ) est passe PUSH $66666666 // directement, mais il faut connaitre la valeur... CALL SommeDouble FSTP R // Dpilage + Stockage du rsultat End; End;

III-E-4 - Type Int64


Les paramtres de type Int64 sont passs par valeur dans la pile dans tous les cas. Le rsultat de type Int64 est retourn dans EDX:EAX. EDX contient les 32 bits de poids fort et EAX contient les 32 bits de poids faible. Fonction :
Function SommeInt64(A,B:Int64):Int64;Register; // [EBP+$10] Valeur de A // [EBP+$08] Valeur de B // Rsultat : contenu dans EDX:EAX Asm MOV EAX,DWORD PTR A ADD EAX,DWORD PTR B MOV EDX,DWORD PTR A[4] ADC EDX,DWORD PTR B[4] End;

- 24 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Appel :
Procedure AppelSommeInt64; Var A:Int64; R:Int64; Asm // Exemple ajout de $1234567890 A et stockage dans R PUSH DWORD PTR A[4] // Il faut commencer par le point fort PUSH DWORD PTR A PUSH $00000012 PUSH $34567890 CALL SommeInt64 MOV DWORD PTR R,EAX MOV DWORD PTR R[4],EDX End;

III-E-5 - Tableaux statiques


Les tableaux sont passs par adresse mme dans le cas d'criture de fonction par valeur. Il convient la fonction appelante de faire une copie du tableau si la fonction est susceptible d'en modifier le contenu. L'emplacement du rsultat doit tre rserv par le programme appelant et il doit passer l'adresse de cette zone en tant que paramtre pointeur supplmentaire. Fonction :
Type TTabInteger=Array[0..3]Of Integer; Function SommeTableau(T1,T2:TTabInteger):TTabInteger; // EAX adresse de T1 // EDX adresse de T2 // ECX adresse de stockage du rsultat Asm PUSH EDI PUSH EBX MOV EDI,ECX XOR ECX,ECX @@L1: MOV EBX,DWord Ptr T1[ECX*4] ADD EBX,DWord Ptr T2[ECX*4] MOV DWord Ptr [EDI+ECX*4],EBX INC ECX CMP ECX,4 JB @@L1 POP EBX POP EDI End;

Appel :
Procedure AppelSommeTableau; Const Tab1:TTabInteger=(1,2,3,4); Tab2:TTabInteger=(4,3,2,1); Var Res :TTabInteger; Begin Asm LEA EAX,Tab1

- 25 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

LEA EDX,Tab2 LEA ECX,Res Call SommeTableau End; End;

III-E-6 - Chanes courtes


Les chanes courtes sont traites comme les tableaux, c'est--dire que les paramtres sont toujours passs par adresse, et que l'emplacement du rsultat doit tre rserv par le programme appelant. Fonction : ( concatnation ici )
Function SommeChaine(A,B:ShortString):ShortString; // EAX contient l'adresse de A // EDX contient l'adresse de B // ECX contient l'adresse de stockage du rsultat // Rem : aucun contrle de longueur n'est effectu !!! Asm PUSH EDI PUSH ESI MOV EDI,ECX // DI pointe sur le rsultat MOV CL,Byte ptr [EAX] // longeur de A ADD CL,Byte ptr [EDX] // longeur de B MOV Byte ptr[EDI],CL // longeur totale INC EDI // Prise en compte longueur MOV ESI,EAX // ESI pointe sur A INC ESI XOR ECX,ECX // ECX = longueur de A MOV CL,Byte Ptr [EAX] REP MOVSB // Copie de A MOV ESI,EDX // ESI pointe sur B INC ESI MOV CL,Byte Ptr [EDX] // ECX = longueur de B REP MOVSB // Copie de B POP EDI POP ESI End;

Appel :
Procedure AppelSommeChaine; Const ST1:ShortString='1234'; ST2:ShortString='5678'; Var Res:ShortString; Begin Asm LEA EAX,St1 LEA EDX,St2 LEA ECX,Res Call SommeChaine End; ShowMessage(Res); End;

- 26 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

III-E-7 - Enregistrements
Les enregistrements sont traits comme les tableaux, c'est--dire que les paramtres sont toujours passs par adresse, et que l'emplacement du rsultat doit tre rserv par le programme appelant. Fonction :
Type TRec=Record rEntier1 : Integer; rEntier2 : Integer; End; Function SommeRecord1(R1,R2:TRec):TRec;Register; // EAX va contenir l'adresse de R1 // EDX va contenir l'adresse de R2 // ECX contient l'adresse de stockage du rsultat Const RecCST:TRec=(rEntier1:3;rEntier2:4); Asm PUSH EBX MOV EBX,TRec([EAX]).rEntier1 ADD EBX,TRec([EDX]).rEntier1 ADD EBX,RecCST.rEntier1 MOV TRec([ECX]).rEntier1,EBX MOV EBX,TRec([EAX]).rEntier2 ADD EBX,TRec([EDX]).rEntier2 ADD EBX,RecCST.rEntier2 MOV TRec([ECX]).rEntier2,EBX POP EBX End;

Appel :
Procedure AppelSommeRecord; Var A:TRec; R:TRec; Const B:TRec=(rEntier1:1230;rEntier2:5670); Asm LEA EAX,A LEA EDX,B LEA ECX,R CALL SommeRecord1 End;

- 27 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

IV - Accder aux objets


C'est la partie la plus dlicate et dont l'application n'est pas possible dans tous les cas. Le programme doit raliser le raisonnement du compilateur pour l'accs aux objets. La porte des membres d'un objet fait qu'il n'est pas toujours possible d'y accder. Nous supposerons dans la suite qu'il n'y a pas de problme de porte dans l'utilisation des membres de l'objet. Dans ce chapitre, l'objet suivant sert d'exemple :
Type TMonObjet=Class Private FValeur : Integer; Fentier : Integer; Protected Constructor Create; Public Function GetValeur :Integer; Function GetValeur2:Integer;Virtual; Function GetValeur3:Integer;Dynamic; Procedure SetValeur(V:Integer); Class Function GetInfo:Integer; Published Property Valeur:Integer read GetValeur Write SetValeur; Property Entier:Integer read FEntier Write FEntier; End;

IV-A - Appel d'une mthode statique


L'appel d'une mthode statique d'un objet est identique l'appel d'une fonction. Par contre toutes les mthodes d'objet ont un premier paramtre implicite qui est l'adresse de l'instance. Par dfaut la convention register s'applique aux mthodes d'objet. La fonction GetValeur est ici une mthode statique et retourne la valeur de la proprit Valeur :
MOV EAX,MonObjet // Paramtre implicite CALL TMonObjet.GetValeur

IV-B - Appel d'une mthode virtuelle


L'appel d'une mthode virtuelle passe par une tape supplmentaire pour obtenir la " table des mthode virtuelles ". La fonction GetValeur2 est ici une mthode virtuelle et retourne la valeur de la proprit Valeur :
MOV EAX,MonObjet MOV EDX,[EAX] // Rcupration de la VMT CALL DWORD PTR [EDX + VMTOFFSET TMonObjet.GetValeur2]

- 28 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

IV-C - Appel d'une mthode dynamique


L'appel d'une mthode dynamique passe par une fonction spciale appelant la mthode.
PUSH ESI // EAX contient toujours l'adresse de l'instance MOV EAX,MonObjet // L'indice de l'entre DMT doit se trouver dans ESI MOV ESI, DMTINDEX TMonObjet.GetValeur3 // Appel de la mthode CALL System.@CallDynaInst POP ESI

IV-D - Appel d'une mthode de classe


Les mthodes de classes sont appeles comme une mthode statique mais n'ont pas de paramtre implicite contenant l'adresse de l'instance. L'appel s'effectue directement sur le type :
CALL TMonObjet.GetInfo

IV-E - Accs aux proprits


Pour accder aux proprits d'un objet, vous devez connatre sa dclaration exacte. Il faut connatre les paramtres read et write de la proprit. Si le paramtre est directement un membre interne, il faut accder ce membre. Si le paramtre passe par une fonction SetXXX ou GetXXX il faut appeler la mthode en question suivant la catgorie de la mthode (virtuelle ou non). Dans l'exemple ci-dessus, la lecture de la proprit Valeur est effectue par :
MOV EAX,MonObjet CALL TMonObjet.GetValeur // EAX contient Valeur

Et l'criture est effectue par :


MOV EAX,MonObjet // Paramtre implicite MOV EDX,2244 // Paramtre explicite CALL TMonObjet.SetValeur

Attention : ces mthodes peuvent tre aussi virtuelles ou dynamiques, il faut dans ce cas appliquer la mthode correspondante. Dans le cas d'une proprit associ directement un membre interne :

Property Entier:Integer read FEntier Write FEntier;


La lecture de la proprit est effectue comme suit :

- 29 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

MOV EAX,MonObjet MOV EAX,[EAX].TMonObjet.Fentier

L'criture de la proprit est effectue comme suit :


MOV EAX,MonObjet MOV [EAX].TMonObjet.Fentier,12345

Les mthodes GetXXX et SetXXX tant dans la plupart des cas prives ou protges et les membres Fxxx privs, il sera dans la plupart des cas impossible d'accder aux proprits des objets de la VCL. Toutes les mthodes prsentes ici sont donnes dans le cas d'criture d'objets personnaliss dont les mthodes sont publiques ou dans le cas d'appel dans la mme unit que celle contenant la dfinition des objets.

- 30 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

V - Cration d'un objet.


Allez, juste pour le fun et afin d'avoir une classe dont le code est entirement en assembleur, voici la mthode suivre pour crer un objet en asm. La suite du document prsente la ralisation d'une classe TMonObjet2 descendante d'une classe TMonObjet. TMonObjet tant crite en pascal ou en asm. D'autre part, tout le code est donn en supposant que register est la convention d'appel. C'est le cas par dfaut dans tous les projets Delphi. La dclaration de TMonObjet2 est la suivante :
Type TMonObjet2=Class(TMonObjet) Private FEntier : Integer; Protected Function GetEntier :Integer; Procedure SetEntier(V:Integer); Public Constructor Create; Destructor Destroy;Override; Class Function MethodeDeClasse:Integer; Published Property Entier:Integer read GetEntier Write SetEntier; End;

V-A - Le constructeur
Le constructeur reoit deux paramtres implicites en plus de ceux donns dans sa dclaration. Le premier paramtre est l'adresse de la description de la classe, cette adresse est directement traite dans le code ajout en dbut de code par la directive asm. Ce code de dbut de constructeur cre l'instance de l'objet et retourne son adresse dans EAX. On admet alors que juste aprs le asm, EAX contient l'instance de l'objet. Le deuxime paramtre est un boolen dfinissant si l'objet doit tre cr. En effet, seul le premier appel du constructeur effectue la cration de l'instance, tout appel ultrieur un constructeur hrit n'effectue aucune cration d'instance. Ce paramtre est transmis dans DL. Il est usage interne de Delphi. Si DL=0, la classe est dj cre et EAX contient alors l'instance de cette classe. Si DL=1, la classe doit tre instancie et EAX contient son descripteur. Attention : ces deux paramtres doivent tre conservs et restitus juste avant le end de fin de code, car le end ajoute du code de finalisation de cration qui ne doit tre excut qu'une seule fois.

- 31 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

De plus le constructeur doit sa sortie laisser dans EAX l'adresse de l'instance cre. Un constructeur simple, ne faisant que mettre jour des variables prives ressemble ceci :
constructor TMonObjet2.Create; // EAX : implicite => contient l'adresse de l'instance // DL : implicite => classe a crer Asm // le code de cration est gr par Delphi MOV [EAX].TMonObjet2.FEntier,12345 end;

En gnral tout constructeur appel son constructeur hrit, ceci est effectu en appelant directement le constructeur de la classe parente. Il faut penser passer en paramtre les deux paramtres implicites en plus des paramtres explicites. Le premier paramtre implicite ( EAX ) doit contenir l'instance de la classe. Le deuxime paramtre implicite ( DL ) doit tre zro, car l'instance est dj cre et ne doit pas tre cre nouveau. Le code du constructeur devient donc :
constructor TMonObjet2.Create; // EAX : implicite => contient l'adresse de l'instance // DL : implicite => classe a crer Asm // le code de cration est gr par Delphi PUSH EDX // Par dfinition le constructeur hrit va conserver EAX XOR EDX,EDX Call TMonObjet.Create MOV [EAX].TMonObjet2.FEntier,54321 POP EDX end;

A noter qu'il n'est pas utile de sauver EAX avec d'appeler la mthode hrite, car par dfinition le constructeur retourne l'adresse de l'instance. L'appel du constructeur hrit ne fait que conserver dans EAX la valeur reue en entre.

V-B - Le destructeur
Le fonctionnement du destructeur est sensiblement le mme que celui du constructeur. Le destructeur reoit deux paramtres implicites en plus de ceux donns dans sa dclaration. Le premier paramtre est l'adresse de l'objet. Le deuxime paramtre est un boolen dfinissant si l'objet doit tre dtruit. En effet, seul le premier appel du destructeur effectue la destruction de l'instance, tout appel ultrieur un destructeur hrit n'effectue aucune destruction d'instance. Ce paramtre est transmis dans DL. Il est usage interne de Delphi.

- 32 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Si DL=0, l'instance ne doit pas tre dtruite Si DL=1, l'instance doit tre dtruite Attention : ces deux paramtres doivent tre conservs et restitus juste avant le end de fin de code, car le end ajoute du code de finalisation de destruction qui ne doit tre excut qu'une seule fois. En gnral tout destructeur appelle son destructeur hrit, ceci est effectu en appelant directement le destructeur de la classe parente. Il faut penser passer en paramtre les deux paramtres implicites en plus des paramtres explicites. Le premier paramtre implicite ( EAX ) doit contenir l'instance de la classe. Le deuxime paramtre implicite ( DL ) doit tre zro, car l'instance ne doit tre dtruite qu'a la fin de l'appel du premier destructeur. Le code du destructeur devient donc :
destructor TMonObjet2.Destroy; // Le destructeur ne doit pas toucher EDX // EAX pointe sur l'instance en cours, et ne doit pas tre modifi non plus. Asm PUSH EDX MOV [EAX].TMonObjet2.FEntier,0 // Appel du destructeur hrit XOR EDX,EDX Call TMonObjet.Destroy POP EDX end;

V-C - Ecriture des mthodes.


Les mthodes doivent tre crites comme toutes les autres mthodes. Le fait qu'elle soit statique, virtuelle ou dynamique ou non ne change pas son code. Par contre toutes les mthodes ont un paramtre implicite qui est l'instance de l'objet. Les mthodes d'accs aux proprits doivent tre crites comme les autres. Exemple de mthode GetXXX
function TMonObjet2.GetEntier: Integer; // Paramtre implicite : EAX contient adresse de l'instance Asm MOV EAX,[EAX].TMonObjet2.FEntier end;

Exemple de mthode SetXXX


procedure TMonObjet2.SetEntier(V: Integer); // Paramtre implicite : EAX contient adresse de l'instance

- 33 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

// Paramtre explicite : EDX contient la valeur de V. Asm MOV [EAX].TMonObjet.FEntier,EDX end;

Il est noter, que si une mthode virtuelle appelle sa mthode hrite, il ne faut pas utiliser l'appel d'une mthode virtuelle comme expliqu dans le IV. Il faut appeler directement la mthode correspondante de la classe anctre comme on le ferait pour une mthode statique.

V-D - Ecriture d'une mthode de classe.


Les mthodes de classe n'ont pas de paramtres implicites. Elles sont crites comme des procdures ou fonctions ordinaires. Exemple :
class function TMonObjet2.MethodeDeClasse: Integer; // Pas de paramtre implicite. Asm MOV EAX,4444 end;

- 34 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

VI - Problmes spcifiques l'assembleur


Ce chapitre prsente quelques problmes de compilation ou d'excution spcifiques l'assembleur en ligne. L'erreur n'tant pas toujours immdiate dans ce cas.

VI-A - Fonction SizeOf()


Pour charger une taille d'objet dans un registre, on est tent de faire :
MOV ECX, SizeOf(MonType)

Or ceci ne provoque pas d'erreur de compilation mais le code gnr est faux. SizeOf utilis en tant qu'oprande assembleur, retourne en permanence la valeur $32. L'criture correcte de la ligne ci-dessus est :
MOV ECX, Type MonType

VI-B - Erreur de codage due OFFSET


L'oprateur OFFSET permet d'obtenir une adresse plutt qu'une valeur. Suivant les cas le rsultat obtenu est erron. Et ceci sans erreur de compilation. OFFSET retourne une mauvaise valeur quand implicitement un registre est utilis (EBP en gnral)
// Exemples de faux appel non signals la compilation Procedure AppelSommeRecordErreur; Var A:TRec; R:TRec; Const B:TRec=(rEntier1:1230;rEntier2:5670); Asm PUSH OFFSET A // Cette ligne est une erreur car A n'a pas une adresse fixe PUSH OFFSET B // Cette ligne est correcte car B est fixe (dans le code ) LEA EAX,R PUSH EAX Call SommeRecord2 End;

Il est donc conseill d'utiliser deux lignes de code au lieu d'une et de se servir de l'instruction LEA :
LEA EAX,B PUSH EAX

Le fonctionnement est le mme, mais la compilation est correcte dans tous les cas.

VI-C - Erreur due un EBP implicite


EBP est ajout implicitement dans les adressage des variables de la pile ou locales. Si dj deux

- 35 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

registres d'index sont utiliss, la ligne ne pourra tre compile.


// Exemple de faux adressage du EBP Procedure CalculSurTableauCarre; Var T:Array[0..9,0..9]Of Integer; Asm PUSH ESI PUSH EDI MOV ESI,(10*4)*9 // ESI va balayer le premier indice @@L1: MOV EDI,(9*4) // EDI va balayre le deuxime indice @@L2: MOV EAX,ESI IMUL EAX,EDI // La ligne suivante ne compile pas car T est [EBP-$00000190] // ce qui ferait [ESI+EDI+EBP-$00000190], or seuls deux // registres sont autoriss MOV DWORD PTR T[ESI+EDI],EAX SUB EDI,4 JGE @@L2 SUB ESI,10*4 JGE @@L1 POP EDI POP ESI End;

Attention : dans les versions antrieures de Delphi, cette ligne se compile sans erreur, mais ne fonctionne pas vu qu'il n'est pas possible d'utiliser trois index. Ceci peut provoquer des rsultats trs bizarres.

VI-D - Erreur d'adresse dans des sous-procdures


Delphi n'utilise pas les fonctions d'entre ENTER et LEAVE pour les imbrications de procdures. Il peut en rsulter que l'adressage des variables des niveaux suprieurs est incorrect. Tant que les instructions PUSH et POP ne sont pas utilises, l'adressage est correct.
// Exemple d'erreur d'adressage du PUSH // avant l'appel d'une sous-procdure Procedure ErreurVariableSousProcedure; Var i,j,k:Integer; Procedure SousProcedure; Var l:Integer; Asm MOV l,1 MOV EAX,l ADD j,EAX // Erreur de compilation // Est compil en ADD [EBP-$04],EAX // EBP pointant sur la cadre de SousProcedure End; Asm PUSH EAX MOV i,1 MOV j,1 MOV k,1 CALL SousProcedure POP EAX End;

- 36 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

- 37 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/

Utilisation de l'assembleur en ligne avec Delphi par Nono40

Conclusion
L'assembleur en ligne reste tout de mme accessoire lors de la programmation Objet, mais dans le cas d'applications graphiques, son utilisation peut apporter un gain de performance important. Reste que l'on peut aussi l'utiliser par plaisir# Afin de se rappeler le temps o nous n'avions pas le choix. Version PDF de cet article : Miroir 1 : Version PDF Dans le cas o le miroir 1 ne fonctionne pas : Miroir 2 : Version PDF

Merci Bloon pour la correction orthographique.

- 38 Copyright 2003Bruno Gurang . Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' 3 ans de prison et jusqu' 300 000 E de domages et intrets. http://nono40.developpez.com/tutoriel/delphi/asm/