1.55k likes | 1.65k Views
Assembleur. Niveaux de programmation. Niveaux de programmation circuit logiques 0/1 --------------------------------------------------------------------------------- unité de traitement micro-instructions
E N D
Niveaux de programmation • Niveaux de programmation circuit logiques 0/1 --------------------------------------------------------------------------------- unité de traitement micro-instructions (UAL, chemins de données) = suite de 0/1 (Unité de commande) micro-pgme = suite de micro-instructions ------------------------------------------------------------------------------------ Codop 111111 000011101010101 langage machine = suite de 0/1 ------------------------------------------------------------------------------------ ADD A,20 assembleur = remplacer les codop JZ 13 par des mnémoniques Djamal Rebaïne
Structure d’un programme assembleur 8086 TITLE nom ; donner un nom au programme PILE SEGMENTSTACK ; déclaration d’un segment de pile ; dont le nom est pile .......... .......... PILE ENDS ; fin de la déclaration de la pile DONNEE SEGMENT ; déclaration d’un segment de données qui va ; contenir les variables ........... DONNEE ENDS ; fin de la déclaration de données LECODE SEGMENT ; déclaration du segment de code qui va contenir ; le code Debut: ; étiquette d’indication du point d’entrée du code ................................. LECODE ENDS ; fin de la déclaration du code END Debut ; fin du point d’entrée du code Djamal Rebaïne
Exemple • TITLE prog2.asm: Exemple sur ROL, • Pile segment stack ; • dw 100 dup(?) • Pile ends • DATA segment • DATA1 DW 5F97H • COMPTE DB ? • DATA ends • CODE segment • MAIN: • ASSUME CS:CODE, DS:DATA • MOV AX,DATA • MOV DS, AX • XOR BL, BL ; Mettre BL à 0 (ou bien SUB) • MOV DL, 16 ; rotation 16 fois • MOV AX, DATA1 • ENCORE: ROL AX, 1 ; Rotation a gauche (a droite aussi si on préfère) • JNC PROCHAIN ; Test si CF=0 • INC BL ; Si CF = 1, incrémenter le compteur du nombre de ‘1’ • PROCHAIN: DEC DL ; répéter 16 fois • JNZ ENCORE ; encore une fois si ce n’est pas fini • MOV COMPTE, BL ; sauvegarder le résultat dans la case mémoire COMPTE • MOV AH, 4Ch • INT 21h • MAIN ENDS • END MAIN Djamal Rebaïne
Pourquoi les segments? À l'origine - Pour pouvoir adresser plus de 64 Ko de mémoire dans un programme car les registres sont sur16 bits En pratique aujourd'hui - Permet de séparer clairement des zones mémoires selon leur rôle Exemple : la pile ne peut pas être écrasée par des données ou déborder sur des données / code Mais cela est contraignant ... Djamal Rebaïne
Suite Adressage sur 20 bits avec 2 registres 2 registres 16 bits : peut coder adresses sur 32 bits Pour uniquement 20 bits - Décale le premier registre de 4 bits et l'additionne au second - Adresse notée A:B - Adresse réelle : A * 16 + B Exemple (les nombres sont en hexa) • 3100:27EE correspond à l'adresse 31000 + 27EE = 337EE • Décaler de 4 bits en binaire revient à décaler d'un chiffre en hexa Djamal Rebaïne
Suite 2 Nous avons 4 segments d'adresses : CS, DS, SS, ES • utiliser 2 registres pour adresser des mots mémoires - Le premier est le registre de segment - Le second un registre général On l'appelle l'offset (décalage) Addresse : segment:offset • Exemples - CS:IP : adresse de la prochaine instruction à exécuter - DS:SI : adresse d'une donnée - SS:SP : adresse du haut de la pile Djamal Rebaïne
Vos programme sources, écrits en assembleur, doivent avoir l’extension .asm pour ASseMbler Djamal Rebaïne
Déclaration de variables Les variables se déclarent de la manière suivante: datas1 db ? ; datas1 est un byte non initialisédatas2 db 0FFh ; datas2 est un byte initialisé à FF (255 en hexadécimal)datas3 dw ? ; datas3 est un word (16 bits)datas4 db 5 dup (?) ; datas4 est un tableau de 5 bytes non initialisésdatas5 dw 10 dup (15) ; datas5 est un tableau de 10 byte initialisés à 15 De manière générale: DB : 1 byte (8 bits) (Declare Byte) DW : 1 word (16 bits) (Declare Word) DD : 2 words (32 bits) (Declare Double) DF,DP : 6 bytesDQ : 8 bytes (64 bits)DT : 10 bytes Les constantes peuvent être écrites en: - décimal: 1, 2, 3, 123, 45 - hexadécimal : 1h,2h,3h,12h,0Fh,0AD4h (noter la présence du 0 quand le le premier chiffre du nombre en hexadécimal commence par une lettre) - binaire : 1b,0b,1010b,111101b Djamal Rebaïne
Les entrées Sorties en assembleur • Pour réaliser les opérations standards (affichage, saisie), le système d’exploitation (ici DOS) fournit les fonctions pré-écrites suivantes: • Affichage d’un caratère: mov DL, “A”; caractère A est transfére dans DL mov AH, 2; fonction no. 2 int 21h ; appel au DOS • Affichage d’une chaine de caractères: mov DX, offset chaine; pointe vers l’adresse du premier caractère de la chaîne de caractères chaine mov AH, 09h; fonction no. 9 int 21h; • Saisie d’un caratère: mov AH, 1; fonction no. 1 (avec écho) int 21h ; résultat est mis dans AL Djamal Rebaïne
Saisie d’un caractère mov AH, 7; fonction no. 7 (sans écho) int 21h ; résultat dans AL • Arrêt de programme: mov AX, 4C00h; int 21h; À mettre à la fin de chaque fin programme; c’est l’équivalent du return (0) en C. Ces instructions ont pour effet de retourner au DOS Djamal Rebaïne
L’équivalent de quelques instructions du langage C en assembleur • if then else Assembleur If ax =1 if: CMP AX, 1 bx = 10; JNZ Else else { bx = 0; Then: MOV BX,10 cx = 10; JMP endif } Else: MOV BX,0 MOV CX,10 endif: .............. Djamal Rebaïne
Instruction i VRAI FAUX Condition ? Instructions m Instructions j Instructions k … Instruction i Siconditionalors Instructions j Sinon Instruction m Fin si Instructions k Djamal Rebaïne
La boucle FOR Assembleur • For (k=0; k<=10; k++) MOV BX,0 • bx = bx + k; MOV CX,0 For: CMP CX,10 JA Endfor ADD BX,CX INC CX JMP For Endfor: Djamal Rebaïne
WHILE Assembleur • bx = 5 MOV BX,5 • while (bx >0) while: CMP BX,0 bx = bx -1; JLE Endwhile DEC BX JMP while Endwhile: Djamal Rebaïne
SWITCH Assembleur • switch (n) { CMP n,1 case 1: ....; break; JNE case2 case 2: .....; break; ............ default: .....; JMP endswitch } case2: CMP n,2 JNE default .......... JMP endswitch default: ........... endswitch: ........... Djamal Rebaïne
Écrire le code de l’instructionEn assembleur if (a>b) && (c <= d) if: cmp a, b { jng endif ................ } cmp c, d jnle endif .............. endif: Exercice: coder en assembleur les instructions suivantes: 1. if (a >b) || (c > d)) 2. for (i=1; i < 10; i++) { { } } Djamal Rebaïne
Liste des registres les plus utilisés A. Registres généraux • AX (A pour accumulateur): joue le rôle d’opérande implicite dans plusieurs opérations: MUL, DIV, INC, etc. • CX (C pour compteur): est utilisé pour les boucles (instruction LOOP). • DX: utilisé dans les multiplications et divisions comme registre d’extension. • SI (Source Index): souvent utilisé comme pointeur sur une adresse mémoire (exemple: MOV AL, [SI]). Il est très utilisée avec les instructions de traitement de chaînes de caractères (LODS). • DI (Destination Index): pareil que SI (instruction STOS) • BP (base pointeur): sert de pointeur sur la base de la pile, et permet d’atteindre n’importe quel élément de la pile (exemple: MOV AX,[BP+2]). • SP (Stack pointer): pointe sur le sommet de la pile; son contenu est automatiquement changé par les instructions PUSH et POP. Djamal Rebaïne
B. Registres spéciaux • IP (Instruction pointeur): contient l’adresse de l’instruction qui suit celle qui est en cours d’exécution. • DS (Data Segment): Pointe sur le début du segment qui contient les données • CS (Code Segment): Pointe sur le segment qui contient le code du programme. • ES (Extended Segment) : permet de pointer sur un segment supplémentaire défini par le programmeur. Il se charge par l’intermédiaire de AX, comme pour DS. • SS (Stack Segment): segment contenant la pile. C. Registre indicateur : utilisé pour sauvegarder des états particuliers du microprocesseur en référence à la dernière instruction exécutée. Quelques bits seulement de ce registre ont une signification sont nommés: CF (retenue), OF (débordement), etc. Djamal Rebaïne
Format standard d’une instruction Label: Mnémonique Opérandes ;commentaire Label: est unidentificateur permettant de désigner un endroit dans le code source, soit une instruction, soit une donnée. Si le label est placé avant une instruction, on fait référence à l’adresse de cette instruction. Si c’est avant une donnée, on fait référence à l’adresse de cette instruction. Le label de code doit se terminer par deux points (:). Il sert général comme destinations des instructions ou des retour de début des boucles de répétition. Le label de donnée ne contient pas les deux points(:) à la fin. Il sert dans ce cas là comme identificateur. Djamal Rebaïne
Mnémonique (des instructions): il sert à identifier une instruction donnée. Quelques instructions de base sont résumées dans la prochaine section. • Opérandes: une instruction assembleur peut avoir de 0 à 3 opérandes. Chaque opérande peut être le nom d’un registre, un opérande mémoire, une expression constante ou le nom d’un périphérique entrée/sortie. • Commentaire: précédé du point-virgule (;). Il sert à à ajouter des informations explicatives au sujet du fonctionnement du programme ou de l’instruction correspondante. Djamal Rebaïne
Quelques instructions de base-1 • Affectations ; Registres <-- Valeurs MOV AX, 65535 ; (décimal) MOV Cl, 01101b ; (binaire) MOV DH, 0FAh ; (hexa) ; Entre registres MOV AX, BX MOV CL, DH ; Entre Registres et Variables MOV CX, variable_de_deux_octets MOV variable_de_un_octet, DL ;Registres <-- Adresses Mémoire Mov AX, Offset variable ; AX <- adresse de variable Mov CX, [ 5Ah ] ; CX <- valeur à l'adresse 5A en hexa Djamal Rebaïne
Quelques instructions de base- 2 • Arithmétique ; Incrémentation INC AX ; AX <- AX + 1 Inc ma_variable ; Décrémentation DEC AX Dec ma_variable ; Addition ADD AX, 5 ; AX <- AX + 5 ADD BH, toto ; BH <- BH + toto Add toto, Cx ; toto <- toto + Cx ; Soustraction SUB AX, 5 ; AX <- AX – 5 SUB BH, toto ; BH <- BH – toto SUB toto, CX ; toto <- toto - CX Djamal Rebaïne
Quelques instructions de base-3 • Logique ; AND bit à bit MOV AH, 0101b ; AH <- 5 MOV BH, 1001b ; BH <- 9 AND AH, BH ; AH <- AH AND BH; AH vaut 0001b, soit 1 ; OR bit à bit MOV AH, 0101b ; AH <- 5 MOV BH, 1001b ; BH <- 9 Or AH, BH ; AH <- AH OR BH; AH vaut 1101b, soit 13 (8+4+1) ; XOR bit à bit MOV AH, 0101b ; AH <- 5 MOV BH, 1001b ; BH <- 9 XOR Ah, BH ; AH <- AH XOR BH; AH vaut 1100b, soit 12 (8+4) ; NOT bit à bit MOV AH, 0101b ; AH <- 5 Not AH ; AH <- NOT AH; AH vaut 1010b, soit 10 (8+2) Djamal Rebaïne
Quelques instructions de base-4 • Comparaisons : Toutes les comparaisons se font à l'aide de l'instruction CMP. On utilise ensuite les instructions de saut conditionnel: Jump if Equal, JMP if Greater, ... Il faut définir des labels (étiquettes): les endroits dans le programme où va sauter si le test est vérifié (comme les GOTO en Fortran). ; Egalité (Jump if Equal) CMP AX, 5 JE label_1 ; Différence (Jump if Not Equal) CMP AX, ma_variable JNE label_2 ;Inférieur, Supérieur, Inf. ou égal, Sup. ou égal ; (Jump if Lower, Greater, Lower or Equal, Greater or Equal) CMP CH, 0 JL label_1 CMP DH, Ah JG label_2 CMP AL, 01001b JLE label_3 Djamal Rebaïne
CMP variable, 65 JGE label_4 Label_1: instructions... Label_2: instructions... Label_3: instructions... Label_4: instructions... ; Saut non conditionnel : JMP label_1 Remarque: CMP est identique à l’instruction SUB, mais ne produit pas de résultat. Il positionne cependant les flags. Il permet de sauter à un label qui est à une adresse de 16 bits. Les sauts à un label sont toujours courts (à peu prés de 127octets). Il faut donc prendre garde que ce label puisse être atteint. Djamal Rebaïne
Modes d’adressage Un mode d'adressage est un moyen qui permet au microprocesseur d'avoir accès à une donnée. Cette donnée peut être un nombre quelconque dont on aura besoin dans le programme, un nombre qui se trouve déjà dans un registre, ou encore un nombre qui se trouve écrit quelque part en mémoire. • La connaissance des principaux modes d'adressage est nécessaire car elle permet d'écrire les programmes de la façon la plus courte, la plus simple et la plus lisible possible. Djamal Rebaïne
Modes d’adressage • Mode immédiat L’opérande est codée avec l’instruction mov AX, 568 • Mode registre L’opérande est un registre de donnée ou d’adresse mov AX,BX • Mode mémoire direct L’opérande est désigné par l’adresse donnée dans l’instruction mov [0hC040],AL mov DS :[0hC040],AL mov CS:var2,AX mais pas mov 0hFE15 :var2,AX Djamal Rebaïne
Modes d’adressage pour accéder aux données • Mode mémoire indirect L’opérande est désignée par une adresse placée dans les registres d’adresses donnée dans l’instruction mov AX,[SI] BX,BP,SI,DI peuvent servir de registre pointeur 1. Indirect avec déplacement L’adresse = contenu du registre d’adresse + déplacement (le registre d’adresse n’est pas modifié) mov AX, [DI] mov BX,[DI+6] Djamal Rebaïne
Modes d’adressage pour accéder aux données 2. Indirect avec index L’adresse = contenu du registre d’adresse + contenu du registre d’index (le registre d’adresse n’est pas modifié) mov [BP][DI],AX les couples possibles sont BP-DI, BP-SI, BX-DI, BX-SI Djamal Rebaïne
Quelques notes utiles • La déclaration d’une chaîne de caractères est mise en '''' ou ' ' . • Le caractère '$' indique la fin d’une chaîne de caractères. Son omission implique que les octets en mémoire qui viennent après cette chaîne sont aussi affichés comme des caractères. • L’assembleur ne fait pas de différence entre une majuscule et une minuscule dans l’écriture de ses instructions et la notation des registres. • La directive ASSUME permet d'indiquer à l'assembleur où se situe le segment de données et le segment de code. Puis il s'agit d'initialiser le segment de données à l’intérieur du segment de code: MOV AX, nom_du_segment_de_donnees MOV DS, AX Djamal Rebaïne
Un petit mot sur l’instruction de transfert MOV reg, reg (registre à registre) reg, mem (registre à mémoire) mem, reg (mémoire à registre) reg, imed (registre à valeur) mem, imed (mémoire à valeur) NOTE: Pas de transfert de mémoire à mémoire Djamal Rebaïne
Applications de quelques instructions sur des exemples Djamal Rebaïne
Instruction CMP(Comparer) CMP destination, source L’instruction CMP affecte les indicateurs AF, OF, SF, PF, CF et ZF mais seuls CF et ZF sont utilisés. L’opérande destination peut être dans un registre ou dans une mémoire. L’opérande source peut être dans un registre, dans une mémoire, ou en mode immédiat. Les opérandes (destination et source) ne changent pas. DATA1 DW 235FH … MOV BX, 7888H ; 7888Hh BX MOV CX, 9FFFH CMP BX, CX ; BX < CX CF=1 JNC est exécutée PASSE JNCPASSE ; Note: les contenus de (BX, et CX) ne changent pas après CMP ADD BX, 4000H PASSE: ADD CX, DATA1 ; mais CF est toujours vérifié pour (< ou >). Pour (=) on utilise ZF. TEMP DB ? … MOV AL, TEMP ; TEMP AL CMP AL, 99 ; TEMP = 99?. Avec (SUB AL, 99), la même chose mais 0 AL JZPROCHAIN ; Si ZF=1 (TEMP=99), Saute a PROCHAIN: INC BX ; Sinon incrémente BX PROCHAIN: HLT ; Arrêt du programme Djamal Rebaïne
TITLE prog1.asm: Exemple sur CMP,Trouver l’octet le plus grand parmi 5 notes d’élèves • PILE segment stack • dw 100 dup(?) • PILE ends • ;------------------------------------------------------------------------------------------------------------------------------------------------------------- • DATA segment • NOTES DB 18, 06, 19, 11, 08 • PLUS_G DB ? • DATA ends • ;------------------------------------------------------------------------------------------------------------------------------------------------------------ • CODE segment • main: • assume CS:CODE, DS:data ; génération de l’adresse du segment de code et de données • MOV AX, DATA ; Initialiser le registre DS pour récupérer l’adresse du segment de donnée • MOV DS, AX • MOV CX, 5 ; compteur de boucle • MOV BX, OFFSET NOTES ; BX pointe vers les données NOTES • XOR AL, AL ; Initialise AL à 0; va héberger la plus grande note • ENCORE: CMP AL, [BX] ; compare la note prochaine a la note la plus élevée • JA PROCHAIN ; Sauter si AL est encore la note la plus élevée • MOV AL, [BX] ; sinon AL retient la plus élevée • PROCHAIN: INC BX ; pointe vers la prochaine note • LOOPENCORE ; CX décrémente jusqu’à 0 pour sortir de la LOOP • MOV PLUS_G, AL ; sauvegarde de la note la plus élevée dans PLUS_G • ;------------------------------------------------------------------------------------------------------------------------------------------------------------- • MOV AH, 4Ch • INT 21h • MAIN ENDS • END MAIN Djamal Rebaïne
TITLE prog2.asm: Exemple sur ROL,Trouver le nombre de ‘1’ dans un mot • Pile segment stack ; déclaration d’un segment de pile – pas nécessaire dans notre cas • dw 100 dup(?) • Pile ends • ;------------------------------------------------------------------------------------------------------------------------------------------------------------ • DATA segment • DATA1 DW 5F97H • COMPTE DB ? • DATA ends • ;------------------------------------------------------------------------------------------------------------------------------------------------------------- • CODE segment • MAIN: • ASSUME CS:CODE, DS:DATA • MOV AX,DATA • MOV DS, AX • XOR BL, BL ; Mettre BL à 0 (ou bien SUB) • MOV DL, 16 ; rotation 16 fois • MOV AX, DATA1 • ENCORE: ROL AX, 1 ; Rotation a gauche (a droite aussi si on préfère) • JNC PROCHAIN ; Test si CF=0 • INC BL ; Si CF = 1, incrémenter le compteur du nombre de ‘1’ • PROCHAIN: DEC DL ; répéter 16 fois • JNZ ENCORE ; encore une fois si ce n’est pas fini • MOV COMPTE, BL ; sauvegarder le résultat dans la case mémoire COMPTE • ;------------------------------------------------------------------------------------------------------------------------------------------------------------ • MOV AH, 4Ch • INT 21h • MAIN ENDS • END MAIN Djamal Rebaïne
Quelques explications L’itération: On peut également transcrire une boucle à l’aide de l’instruction LOOP nécessitant l’utilisation implicite du registre CX. MOV CX, unevaleur Boucle: …… ; le corps de la boucle LOOP Boucle Cela signifie que le corps de la boucle est exécuté tant que la valeur de CX n’est pas nulle. A chaque itération, CX est décrémenté d’une unité. Attention: si CX est nul au premier tour, alors il décrémenté et sa valeur devient 65535, et on va attendre un bon bout de temps pour arriver à la valeur nulle et sortir de la boucle Djamal Rebaïne
for (cx=5; cx>0; cx--) ax = ax + cx MOV AX,0 MOV CX,5 ; CX est le compteur de boucle for: ADD AX,CX ; fait le calcul LOOP for ; décrémente d’une unité CX. ; si CX > 0 fait le saut à for Djamal Rebaïne
On peut aussi utiliser LOOPE/LOOPZ/LOOPNE/LOOPNZ pour signifier : a.LOOPE (« Loop while Equal ») Monlabel Décrémente CX, puis, si CX <> 0 et ZF = 1, fait un saut à MonLabel. Mnémonique équivalent : LOOPZ b. LOOPNE (« Loop while not Equal ») Monlabel Décrémente CX, puis, si CX <> 0 et ZF = 0, fait un saut à • MonLabel. Djamal Rebaïne
Buffer DB 8 DUP(0) …….. Boucle: MOV AH,1 ;lecture INT 21h MOV [BX], AL; rangement de qu’on vient de lire INC BX CMP AL, 0Dh; a-t-on lu le retour chariot? LOOPNE Boucle; sinon on continue jusqu’à CX = 0 ???? Djamal Rebaïne
Décalage et rotation • SHL (Shift Left; SHR: shift right): effectue un décalage à gauche des bits. Si le deuxième opérande est une valeur, alors seule la valeur 1 est acceptée. Le bit de poids fort se retrouve dans CF; un 0 est introduit dans le bit de poids faible. • SHL AL, 1 • Une façon plus élégante consiste à utiliser CL dans son rôle de compteur: MOV CL, 4 • SHL AX,CX • Pareil pour les instructions SAR, ROR, RCR et leurs équivalents à gauche. Djamal Rebaïne
Manipulation de données • Operateur offset: renvoie l’adresse à laquelle est située un label de donnée Exemple: …… Bval db ? Wval1 dw ? Wval2 dd ? … … Si Bval se trouve à l’adresse offset 00404000 (hexa), l’opérateur offset renvoie les valeurs suivantes: MOV AX, offset bval ; AX = 00404000 MOV AX, offset Wval1 ; AX = 00404001 MOV AX, offset Wval2 ; AX = 00404002 2. Operateur PTR: Permet de passer outre la taille déclarée au départ pour un opérande. Par exemple, … double dd 12345678h … MOV AX, double; erreur Mais si on insère la directive WORD PTR, on peut copier le mot de poids faible (5678h) dans AX; c’est-à-dire MOV AX WORD PTRdouble Djamal Rebaïne
Un mot sur les macros Étant donné que certaines instructions se répètent constamment dans un programme, l’écriture de macro-fonctions (ou macros) est un moyen pratique de rendre votre code source plus lisible. Il est possible de choisir pour certaines suites d’instructions un nom qui les représente. Lorsque l’assembleur rencontrera ce nom dans votre code source, il le remplacera par les lignes de code qu’il désigne. Ces lignes forment une « macro ». Djamal Rebaïne
Les macros, à la différence des procédures, n’ont aucune signification pour la machine. Seul l’assembleur comprend leur signification. Elles ne sont qu’un artifice mis à la disposition du programmeur pour clarifier son programme. Lorsque l’assembleur rencontre le nom d’une macro dans votre code, il le remplace par le code de la macro. Tout se passe exactement comme si vous aviez tapé vous-même ce code à la place du nom de la macro. • Ainsi, si vous appelez quinze fois une macro dans votre programme, le compilateur écrira quinze fois le code de cette macro. C’est toute la différence avec les fonctions qui ne sont écrites qu’une seule fois mais peuvent être appelées aussi souvent qu’on veut à l’aide d’un CALL (qu’on verra plus tard dans ce cours). Djamal Rebaïne
Voici comment écrire une macro : • l’exemple suivant sert à écrire un message à l’écran. Djamal Rebaïne
affiche macro chaine ; sauvegarder le contenu de DX, par ; exemple, en utilisant la pile push dx ; sauvegarde de dx dans la pile mov dx,offset chaine mov ah, 09h int 21h pop dx ; restauration de dx endm ;fin de la macro Djamal Rebaïne
L’assembleur se chargera alors de la remplacer par les instructions comprises entre la première et la dernière ligne de cet exemple, en prenant le soin de remplacer le mot chaine par le message fourni en paramètre. • Supposons à présent que l’on veuille écrire à l’écran le message « Coucou ! Ceci est un essai » et revenir à la ligne à l’aide de notre macro affiche • La syntaxe suivante : • affiche ‘Coucou ! Ceci est un essai !’, 10, 13, ‘$’ • 10, 13 est l’équivalent de endln en C-C++ Djamal Rebaïne