En ce moment, je bidouille le format EXE. Le mot 12h d'un en-tête EXE (format MZ pour DOS) comporte le complément à un du checksum : cela signifie que l'addition sans retenue de tous les mots du fichier EXE (en-tête compris) donne FFFFh. Pour l'obtenir, LINK calcule d'abord le checksum avec le mot 12h nul :
http://bytepointer.com/download.php?nam ... xe_com.pdf
http://www.tavi.co.uk/phobos/exeformat.html
Je vais infirmer une de mes vieilles suppostions :
Il est très simple de la faire avec le fichier ASM.EXE car son contenu tient dans un segment de mémoire. Il faut d'abord supprimer l'extension EXE pour forcer DEBUG à le charger comme un fichier binaire :
Citation : - l'équipe Microsoft pour IBM ne savait pas quelle désignation donner à la directive !
Code : Tout sélectionner ren ASM.EXE *. |
Code : Tout sélectionner debug asm < asm.txt |
Nous en déduisons que Microsoft a supprimé a posteriori la directive 286P, certainement pour mettre en avant sa version 3.00 par rapport à IBM :
http://bytepointer.com/masm/index.htm#MASM_3.0
D'ailleurs, heureusement que le DOS ne faisait pas usage de la somme de contrôle. Les fichiers ASM.EXE et MASM.EXE en version 2.00 (IBM) étaient théoriquement invalides. Il aurait été plus sage de remettre un mot nul à l'offset 12h de l'en-tête EXE :
http://www.fysnet.net/exehdr.htm
Samedi 7 mars
Avec le temps, même Microsoft préféra laisser un mot nul à l'offset 12h. Dans les cas contraire, le complément à un de la nouvelle somme de contrôle donnera zéro (NOT FFFFh) si le fichier EXE n'est pas altéré.
Voici un programme en QBasic pour MASM.EXE :
Code : Tout sélectionner M$ = "Somme de contrôle correcte." C$ = "Nouvelle somme de contrôle..." E$ = "Mauvaise somme de contrôle !" FICHIER$ = "MASM.EXE" OPEN FICHIER$ FOR BINARY AS #1 IF LOF(1) = 0 THEN CLOSE : KILL FICHIER$: PRINT FICHIER$; " absent !": SYSTEM FOR OCTET& = 1 TO LOF(1) STEP 2 GET #1, OCTET&, MOT% IF OCTET& = &H13 THEN CONTROLE% = MOT% 'Offset 12h LET SOMME& = (SOMME& + MOT%) AND &HFFFF& NEXT SOMME% = NOT VAL("&H" + HEX$(SOMME&)) IF SOMME% THEN IF CONTROLE% = 0 THEN PUT #1, &H13, SOMME%: M$ = C$ ELSE M$ = E$ PRINT M$ PRINT "NOT Checksum : "; HEX$(SOMME%); " ("; FICHIER$; ")" SYSTEM |
Code : Tout sélectionner A>QBASIC /RUN CHECKSUM Mauvaise somme de contrôle ! NOT Checksum : 100 (MASM.EXE) |
Lundi 9 mars
Bug de l'encodage de l'instruction 186 PUSH imm. remarqué par Charles Petzold :
http://books.google.fr/books?id=FC-L2faxEVkC&pg=PA326
http://books.google.fr/books?id=-9qzy8Z ... VQR&pg=292
Dans les versions 2.0 et 3.0 de MASM, l'instruction ADD AX,68h entre en jeu.
Après pistage de la valeur 1234h (test d'assemblage de PUSH 1234h) grâce à DEBUG et au désassemblage de MASM 2.0, je suis tombé sur le code incriminé en SEG+15h:3762h.
Samedi 14 mars
ASM.EXE, qui ne gère aucun code autre que 8086, incorpore pourtant la portion qui teste la suffisance d'un octet signé pour stocker un mot. Bien qu'elle soit utilisée, elle ne cause pas de bug à l'instruction CPM reg16≠AX,imm.
Par contre, il n'y a plus de test pour savoir si on a affaire à l'instruction PUSH imm., inexistante pour le 8086. On le voit en comparant le code en CS+124h:4FF5h avec celui de MASM 2.0 en CS+125h:5D34h. La valeur immédiate, d'une longueur d'un octet dans le pire des cas, est traduite en offset sans émettre de message d'erreur.
Le surlendemain
On remarque que l'instruction fictive POP imm. est malencontreusement traduite en PUSH imm. par MASM.
Jeudi 19 mars
À en croire Roger Schlafly, d'anciennement Borland International, l'option /ML apportée par MASM 3.0 altère la traduction d'une instruction 8087 écrite en minuscules.
Les lendemain et surlendemain
Je voulais m'attaquer au message manquant que pointait Roger Schlafly. C'est un problème commun à MASM 2.0, évidemment. Lorsque deux opérandes ST suivent une instruction 8087, MASM ignore le fait que l'un des deux ne soit pas le numéro zéro. Au lieu d'émettre un message d'erreur, il suppose que le deuxième est ST(0). MASM 5, lui, signale "error A2052: Improper operand type" comme lorsque l'opérande n'est pas un registre.
On peut traquer la gestion d'erreur, dans MASM 2.0, en en provoquant une. Il n'existe pas de registre ST dont le numéro va au-delà de 7. D'ailleurs, un éventuel signe moins provoquera aussi une "50:Value is out of range" à la deuxième passe.
En temps normal, le test remplace la valeur du premier opérande par le second. Il y en a forcément un de nul en absence de faute. Cela n'interfère pas avec les instructions 8087 n'ayant qu'un seul opérande : MASM met préalablement à zéro la destination.
Revenant au problème particulier de MASM 3.0, l'assembleur s'attend à ce que la deuxième lettre de l'instruction FLD soit une majuscule (comparaison en CS+125:50F3). D'où ce stupide bug qui demeure dans MASM/2.
Lundi 30 mars
Au retour de cette routine, on remarque que MASM a déjà traité l'instruction et qu'il n'a besoin de connaître que le numéro du registre autre que zéro. C'est pourquoi FMUL ST(n),ST(x) devient FMUL ST(n),ST. En intervenant ici, on laisserait le soin à l'erreur "63:Operand combination illegal", qui apparaît lorsque le dernier opérande des instructions 8087 à suffixe P n'est pas ST(0), d'être traitée ailleurs : FADDP ST(n),ST est par exemple valide.
Toutefois, on en reste là. Comme avec le bug commenté par Microsoft à propos de DUP (offset Variable) qui existe encore dans MASM 3.0 : DUP (Variable) évite que LINK signale une erreur voire, avec une version récente, remplace la valeur à répéter par zéro.
Dimanche 5 avril
Les fonctions de conversion numérique de la bibliothèque IBMUTIL.LIB sont expliquées dans l'ouvrage L'Assembler per l'80286/80386 :
L'indicateur du code en CS+125h:3762h est bon. Il renseigne les instructions SAR, SHL & SHR du 80186 que la valeur immédiate tient dans un entier 8 bits non signé. Le code en CS+125h:6785h de l'instruction CPM reg16≠AX,imm le remplace par l'inverse de l'indicateur précédent :
Code : Tout sélectionner mov ax,[si+0Dh] xor al,1 mov [si+0Ch],al |
Dimanche 17 mai (pile mise à jour à l'Armistice)
Le macro assembleur Microsoft.
SID de Digital Research accepte l'écriture de fichiers EXE, ainsi que l'arithmétique des segments de mémoire.
Microsoft MASM 1.27 avec correction du format LST en 80 colonnes (Page Symbols-1 sur une seule ligne) et du bug de l'an 2000 :
Code : Tout sélectionner A>QBASIC /RUN CHECKSUM Nouvelle somme de contrôle... NOT Checksum : EEAC (MASM.EXE) A>QBASIC /RUN CHECKSUM Somme de contrôle correcte. NOT Checksum : 0 (MASM.EXE) |
L'assembleur IBM.
DEBUG returne la taille du fichier binaire dans les registres BX:CX, avec BX nul s'il tient dans un seul segment de mémoire.
IBM ASM 2.00 avec rétablissement de l'erreur PUSH imm (8086)--ainsi que du code d'erreur 52 pour SAL/SAR/SHL/SHR reg,|imm|≠1 au lieu de 50--et correction du bug de l'an 2000 :
Code : Tout sélectionner -g80 9B AX=0000 BX=0000 CX=CBDA DX=B889 SP=FFEE BP=0000 SI=CCDA DI=0000 |
Ajout du 7 novembre : IBM MASM 2, MS MASM 3 et suivants signalent une valeur immédiate supérieure à 255 par l'erreur 50:Value is out of range. Malencontreusement, IBM ASM 2 l'utilise à la place de 52:Improper operand type pour un opérateur autre que |imm|=1 ou CL. D'où une nouvelle ligne au patch.
Mardi 10 novembre
Les premières versions de MASM débutaient avec une pile de 20 octets sans allocation requise (SP=14h & MIN-ALLOC=0). De plus, le lancement calculait une nouvelle pile en arithmétique signée. Ce qui fausse le résultat à partir de 512 Ko de mémoire allouable aux données :
http://www.os2museum.com/wp/pascal-out-of-memory/
MASM 1.25 étant compilé avec une autre version de PASCAL, le problème semble résolu : une pile de 128 octets est fixée dans une zone allouée (SP=80h & MIN-ALLOC={8;9;Ah}) et l'arithmétique pour en calculer une nouvelle est non signée. Toutefois, CREF reste compilé à l'ancienne.
Finalement, il s'est révélé que seuls MASM & CREF 3.0 étaient fiables de cette manière. Les versions précédentes continuant à se planter si la mémoire était un peu juste. C'est pourquoi il aurait été préférable d'allouer la pile de 2 Ko du compilateur PASCAL, donc de la pointer à l'offset 10h de l'en-tête EXE et d'indiquer l'équivalent en paragraphes supplémentaires à l'offset Ah : SP=800h & MIN-ALLOC={80h;81h;82h}. En outre, c'est ce que LINK /STACK:2048 imposerait sachant qu'une taille quelque supérieure sera fixée au lancement de MASM ou d'ASM (IBM).
Nous remarquons que la fin de MASM 1.27 comble le dernier paragraphe par des valeurs non initialisées (déduites de la taille), alors qu'ASM 2.00 voit sa chaîne finale suivie par seize octets plus un initialisés à zéro. Notre correction du bug de l'an 2000 repousse la fin de fichier telle qu'elle est notée dans l'en-tête EXE (taille modulo 512 à l'offset 2) : deux octets pour MASM et quatre pour ASM.
P.S. : nouveau confinement, nouveau bidouillage.
Format EXE :
Code : Tout sélectionner 00h MZ sinon ZM 02h Longueur du fichier modulo 512 04h Taille du fichier en nombre de pages 06h Nombre de relogements 08h Taille de l'en-tête en paragraphes 0Ah MIN-ALLOC en paragraphes 0Ch MAX-ALLOC (altérable par LINK /CPARMAXALLOC) 0Eh Déplacement du segment de pile par rapport au programme 10h SP à l'entrée (altérable par LINK /STACK) 12h Complément à un du checksum 16 bits sinon 0 14h IP à l'entrée 16h Déplacement du segment de code par rapport au PSP 18h Offset du premier relogement 1Ah Numéro d'overlay (0 si partie résidente) 1Bh Espace réservé (taille variable) ... Table de relogement ... Espace réservé (taille variable) ... Segments de code et de données ... Segment de pile |
Ajout du vendredi 27/11 :
http://ftpmirror.your.org/pub/misc/ftp. ... R/MASM/KB/