Vendredi 24 Octobre 2014
Restauration audio
Une fois de plus, c'est l'anniversaire de Folco. Et comme je sais qu'il aime bien que je mette à jour mon blog, c'est parti !

La première image qui vient à l'esprit quand on parle de restauration audio, ce sont des vieux vinyles poussiéreux qui crachotent, ou des bandes magnétiques en état de décomposition plus ou moins avancé. Pourtant, même avec les procédés et appareils actuels, il peut arriver qu'un enregistrement soit endommagé et qu'il faille donc le restaurer.

Un ami m'a envoyé un enregistrement d'un cours d'université fait avec un smartphone, en utilisant un logiciel sous Android. Malheureusement, le réglage de la sensibilité du micro dans le logiciel était trop élevé, et le signal a été dégradé. Résultat : il y a des craquements très pénibles dès que la voix s'élève (j'ai réduit le volume, mais soyez prudents quand même) :

Il m'a donc demandé s'il y avait un moyen de corriger ça.

Posté à
04:09
 par Zerosquare -
Mercredi 23 Octobre 2013
N'anniv Folco !
Quoi de mieux pour fêter dignement l'anniversaire de Folco qu'un petit programme kernel ?

Écouteurs branchés sur le port link fortement recommandés. Le son ne semble pas marcher avec VTI, mais c'est pas fait exprès. Fonctionnement sous TiEmu et PedroM non testé. Dans la limite des stocks disponibles.

Et pour ceux qui n'ont pas le matos qui va bien sous la main, il y a une version vidéo.

Les sources au prochain épisode...
Posté à
00:07
 par Zerosquare -
Dimanche 05 Mai 2013
AMLD 3 - Hardware
Note pour Folco, qui me réclame - à juste titre - une mise à jour de ce blog depuis fort longtemps : ceci n'est pas le billet dont je t'ai parlé, c'est un bonus qui n'était pas prévu #hehe#

Je dépoussière aujourd'hui ce blog car je me suis aperçu d'une zone d'ombre majeure dans mes précédents articles sur l'AMLD (si vous ne voyez pas de quoi je parle, (re)lisez les anciens billets). On pourrait en effet croire, à la lecture de ceux-ci, que l'AMLD ne peut s'appliquer qu'au développement logiciel. Or ce n'est pas du tout le cas : il s'agit d'une méthodologie polyvalente susceptible de s'intégrer dans n'importe quel design workflow, indépendamment de ce dernier. On peut par exemple appliquer l'AMLD sans difficulté dans la conception de matériel électronique, comme je vais le montrer dans la suite de cet article.
Posté à
03:46
 par Zerosquare -
Jeudi 15 Septembre 2011
Obfuscated C contest
Cela fait plus d'un an que je n'ai rien posté dans ce blog. Ce n'est pas faute d'idées de sujets sur lesquels écrire, mais un subtil mélange de manque de temps à y consacrer et de flemme plus ou moins aiguë selon les jours.

Folco ayant récemment exprimé sur IRC son désir de lire un nouveau billet de blog en prenant son café demain matin, et ne voulant pas le décevoir, je me vois donc dans l'obligation c'est avec grand plaisir que j'en rédige un.

Comme je reste fainéant, il s'agit en fait d'un truc que j'avais préparé il y a longtemps ; et je vais même avoir l'audace de vous mettre à contribution, un peu comme ces artistes qui font chanter leur public %)

Vous connaissez certainement l'Obfuscated C contest, un concours dont le but est d'écrire un programme valide en C qui soit le plus illisible possible. Mais il faut aussi que le programme lui-même soit intéressant à faire tourner et à analyser, sinon c'est beaucoup trop facile :p

Voici donc un programme que j'ai écrit sur ce thème. Pas d'obfuscation à grand coups de #define, de noms de variables abscons ou d'usage tordu des features du compilateur ici ; il ne s'agit "que" d'un algorithme tordu avec les constantes en dur :
Posté à
01:53
 par Zerosquare -
Samedi 28 Aout 2010
AMLD (2)
(si vous n'avez pas lu la première moitié de ce billet, cliquez ici)

Voici la seconde et dernière partie de ce guide destiné à faire de vous un programmeur dont on se souviendra :
Posté à
10:43
 par Zerosquare -
Vendredi 23 Juillet 2010
Taijitu
Aujourd'hui, un peu d'électronique.
(ne vous inquiétez pas, la deuxième partie d'AMLD n'est pas annulée, juste reportée)

Récemment, Microsoft a annoncé une technologie nommée InstaLoad, permettant de créer des appareils qui fonctionnent indépendamment du sens dans lequel sont insérées les piles.

Idée originale et intéressante, mais :
- ça utilise des contacts mécaniques particuliers qui ne sont pas forcément compatibles avec la forme de toutes les piles
- c'est Microsoft, donc brevet, licence, etc.

Du coup, je me suis demandé si on pouvait faire la même chose différemment, par exemple de manière entièrement électronique. Et bien... oui. Et c'est même assez simple.

J'ai nommé ce circuit "Taijitu" (je vous laisse chercher pourquoi #hehe# ), et au cas où ça intéresserait quelqu'un, je le mets dans le domaine public %)

Le schéma se compose en tout et pour tout de 4 transistors :
img


Et voilà ce que ça donne en vrai :
img


Normalement, il faudrait répéter ce circuit pour chaque pile. Comme je suis à court de composants, je l'ai appliqué ici à un bloc de 4 piles.

Une petite vidéo de démo (désolé pour la qualité médiocre, mon appareil photo est très mauvais en vidéo) :

(ceux qui ont de bons yeux pourront voir un "Mem cleared", c'est normal, la pile de sauvegarde de ma TI-83 est morte :p )
Posté à
23:31
 par Zerosquare -
Lundi 05 Avril 2010
AMLD (1)
Vous en avez marre qu'on vous bassine avec la portabilité, la compatibilité ascendante, et autre concepts de consultants en costards Hugo Boss ?
Vous voulez coder pour les machines d'aujourd'hui, pas celles d'hier ni celles de demain ?
Vous ne reculez devant rien si ça peut vous faire gagner quelques cycles ?

Bravo ! Vous êtes mûr pour appliquer la méthode de développement AMLD : Advanced Modeling of Lifecycle Dynamics (soit, en français : Après Moi, Le Déluge).
L'AMLD possède un double avantage : d'une part, elle vous permettra d'exploiter de façon optimale votre machine ; d'autre part, de par sa stabilité comparable à celle d'un élément radioactif, elle vous assurera une certaine sécurité de l'emploi à l'avenir (à défaut, vous aurez la joie d'avoir contribué à empoisonner la vie de votre successeur).

(À ce sujet, une remarque importante : certains pourraient être tentés d'utiliser des chausse-trappes tels que les commentaires illisibles, les noms de variable trompeurs, etc. Cela n'a rien à voir avec l'AMLD, car si le second critère est effectivement rempli, le premier ne l'est absolument pas. De plus, on pourrait vous accuser de sabotage. Aucun risque de ce genre en pratiquant l'AMLD : vous aurez des arguments solides pour affirmer que ce qui cause tant de problèmes aujourd'hui était la meilleure solution au moment où vous avez écrit le code.)

Rassurez-vous : pour maîtriser la méthodologie AMLD, nul besoin d'acheter de coûteux ouvrages ou d'assister à des séminaires ennuyeux à Lewarde (2 770 habitants, attractions principales : sa fête de la châtaigne et sa mine de charbon désaffectée). Pas de copyright, d'examen ou de certification non plus. Tout ce que vous avez à faire, c'est lire la suite de cette news.
Posté à
12:41
 par Zerosquare -
Lundi 22 Mars 2010
Histoires de tire-bouchons
Extrait de la datasheet d'un processeur MIPS :

The word ‘‘endianness’’ was introduced by a famous short paper in the Journal of the ACM, in the early 1980’s. The author observed that computer architectures had divided up into two camps, based on an “arbitrary” choice of the way in which byte and word addressing are related. In ‘‘Gulliver’s Travels’’ the little-endians and big-endians fought a war over the correct end at which to start eating a boiled egg; a war notable for the inability of the protagonists to comprehend the arbitrary nature of their difference. The joke was appreciated, and the name has stuck.

Toutes les époques de l'informatique ont eu leurs sujets de troll débats passionnés : Atari ou Amiga ? Mac ou PC ? Java ou C# ?

Si vous trouvez ces controverses stériles, sachez qu'on a fait mieux : little-endian ou big-endian ?

Rappelons brièvement les faits (je pense que la plupart des lecteurs de ce blog n'en ont pas besoin, mais sait-on jamais). Dès qu'on veut stocker des entiers de plus de 8 bits, il y a deux façons possibles d'ordonner les octets :

- big-endian : on commence par l'octet de poids le plus fort. Par exemple, le nombre 12345678 (en hexadécimal) sera représenté par la suite d'octets 12 34 56 78. C'est le choix qu'a fait Motorola, entre autres.

- little-endian : on commence par l'octet de poids le plus faible. 12345678 sera représenté par la suite d'octets 78 56 34 12. C'est le choix qu'a fait Intel, entre autres.

(il y a aussi des machines qui ont choisi d'autres solutions, par exemple 34 12 78 56, sans parler de celles qui n'utilisent carrément pas des multiples de 8 bits. Elles ont heureusement fini au placard il y a longtemps, juste retour des choses pour avoir pourri la vie des pauvres âmes à la conquête du Graal d'une portabilité parfaite de leurs programmes C.)

Avouez qu'en matière de désaccord, on a déjà vu des questions plus fondamentales. D'autant qu'il ne semble y avoir d'argument significatif pour aucun des deux camps ; à vrai dire, je n'en connais que deux :

- en big-endian, la notation correspond à celle habituelle pour les nombres, c'est donc plus facile à déchiffrer quand on regarde un dump mémoire à 3h du matin parce que le @!#~ de programme a encore planté.

- en little-endian, si on déréférence un pointeur avec une taille inférieure à celle de la donnée pointée (par exemple, qu'on traite un pointeur sur un entier 32 bits comme un pointeur sur un entier 8 ou 16 bits), on récupère les bits inférieurs de la valeur, puisque les bits les moins significatifs sont toujours en premier. On a donc l'équivalent "gratuit" d'un cast en C, et ça fonctionne quelle que soit la taille de la donnée d'origine.

C'est assez anecdotique, et ça ne fait pas vraiment pencher la balance d'un côté plus que l'autre.
Certains fabricants, comme ARM, MIPS ou Atari (sur la Jaguar) ont d'ailleurs choisi une neutralité helvète et leurs processeurs sont capables de gérer aussi bien le big-endian que le little-endian. (avis à ceux qui s'imaginent déjà toutes sortes de hacks tordus sur leur nSpire : si le processeur peut gérer les deux formats, ce n'est généralement pas le cas du reste du matériel qu'il y a autour.)

Même Intel a fini par s'y mettre timidement, même s'il a fallu attendre le 486 : l'instruction bswap permet d'inverser l'endianness du contenu d'un registre.


On retrouve également cette question du choix de l'ordre dans la syntaxe des instructions :

- Motorola a choisi l'ordre opcode source, cible
- Intel a choisi l'ordre opcode cible, source

Les habitués du 68k trouvent généralement que "leur" choix est plus naturel. Pourtant quand on regarde la plupart des langages de "haut niveau" (par rapport à l'assembleur), que voit-on ?

a = 3
b = b + 5

Hé oui, la cible est à gauche et la source à droite ;)

Personnellement j'utilise les deux formats, puisque je bricole en assembleur sur plusieurs processeurs différents.
C'est moins casse-gueule qu'on pourrait le croire, avec un peu d'habitude on arrive à switcher entre les deux sans trop de difficulté. Mais ça arrive quand même d'inverser source et destination par inadvertance (et quand on relit, on a tendance à "voir" le sens qu'on attend au lieu de celui qui est réellement écrit).

Ah, et je confirme que la syntaxe AT&T de GNU as est pourrie en mode 68k, et ultra-pourrie en mode x86 :D


Pour conclure :
img


Et vous ? Avez-vous des arguments pour préférer little-endian/big-endian/source d'abord/destination d'abord ?
Posté à
05:18
 par Zerosquare -
Mercredi 17 Mars 2010
Fonds de tiroirs
Sur les processeurs, il y a des features dont on se sert tout le temps et d'autres qui sont plus anecdotiques. Et souvent, il y a aussi des machins dont tout le monde oublie l'existence, pour différentes raisons que je vais évoquer dans la suite de ce billet. Je parlerai ici essentiellement des x86, vu que je ne connais pas assez les autres processeurs ; si vous avez des exemples à ajouter, je suis preneur.


On peut classer ces features dans au moins trois catégories :


1) les features qui étaient une bonne idée à priori, mais qui ont fait un bide

Le jeu d'instructions x86 s'alourdit à chaque génération de processeur, à tel point que la description occupe maintenant plusieurs centaines de pages. Inutile de dire que tout n'a pas eu le succès escompté...

- l'instruction loop. Elle décrémente le registre (e)cx et saute à un label si le résultat n'est pas nul. C'est grosso modo l'équivalent du dbra sur 68k (à ceci près que la condition de fin est 0 et non -1) ; autrement dit, la brique de base de beaucoup de boucles. Particularité intéressante : les flags ne sont pas altérés, et il existe deux variantes (loopz et loopnz) qui ajoutent comme condition nécessaire à l'exécution de la boucle le fait que le flag Z soit égal à 0 ou à 1. Elle avait tout pour être un succès, cette instrucion-là, non ?
Et pourtant, pour une raison que j'ignore, presque personne ne s'en est jamais servi : les programmeurs et les compilateurs ont préféré un dec (e)cx suivi d'un jnz label. Peut-être par ce que cette séquence est adaptable à d'autres registres, alors que loop ne peut utiliser qu'(e)cx ? Toujours est-il qu'Intel a préféré optimiser le nombre de cycles d'exécution de la paire dec/jnz plutôt que loop, ce qui fait que cette dernière est devenue de plus en plus lente en comparaison. Vous devinez la suite...

- les instructions bound qui déclenche une exception si la valeur d'une donnée dépasse un minimum ou un maximum, et sa consœur into qui fait de même si un overflow s'est produit lors de l'opération arithmétique précédente. Très pratique pour détecter un index qui dépasse les bornes d'un tableau par accident, par exemple. Hélas, à ma connaissance, quasiment personne ne les a utilisées. Il me semble même que sur les processeurs récents, les opcodes correspondant à ces instructions ont été réutilisés pour faire de la place à des nouvelles.

- l'instruction enter qui copie le pointeur de pile dans un autre registre puis qui lui soustrait un nombre d'octets passé en paramètre (leave fait l'opération réciproque). C'est une séquence d'instructions qu'on trouve très souvent au début des fonctions, pour allouer de l'espace mémoire pour les variables locales tout en gardant un pointeur sur les paramètres passés sur la pile. Il semble pourtant que les compilateurs aient snobé ces instructions pour une raison quelconque. On ne les trouve que dans quelques vieilles applications sous DOS.


2) les features qui laissent dubitatif ("à quoi ça peut bien servir ?")

- le bit P du registre de flags, qui est à 1 si le résultat de l'opération précédente contient un nombre pair de bits à 1. À part pour faire un contrôle d'erreur élémentaire (dans les protocoles de communication série, notamment), ce n'est pas quelque chose qu'on utilise fréquemment. Pourtant ce bit existe depuis le 8088, à une époque où l'on ne s'amusait pourtant pas à gaspiller des transistors pour rien. Pourquoi ? Mystère.

- l'instruction invd. Efface le contenu des caches du processeur, mais sans mettre à jour la RAM si le contenu du cache et de la RAM diffèrent. Autant dire que c'est un très bon moyen de provoquer des plantages subtils ! (la documentation met clairement en garde contre les effets néfastes de cette instruction, et il existe une version qui maintient la cohérence cache/RAM : wbinvd). Il ne semble pas y avoir d'application concrète à part pour des tests, probablement des cas tordus.


3) les features recyclables

Parfois, une feature à priori sans grand intérêt peut trouver une application inattendue.

- l'instruction hlt arrête le processeur et attend qu'une interruption se produise, de façon similaire à stop sur 68k. C'était rarement utilisé sous DOS, et plus du tout sous Windows : ça n'a pas d'intérêt quand on n'accède pas au hardware directement, et de toute façon l'instruction n'était pas exécutable par les applications (réservée aux drivers et au système). Jusqu'à ce que quelqu'un s'aperçoive qu'un processeur dans cet état consommait nettement moins, et par conséquent dégageait moins de chaleur. Un thread avec la priorité la plus basse possible (pour qu'il ne s'exécute que quand il n'y a rien d'autre à faire), un mini-driver qui ne fait qu'exécuter cette instruction, et hop : au lieu de gaspiller les cycles inutilisés, on met le processeur en pause. On trouvait ainsi des petits programmes pour Windows 95 pour diminuer la température de son PC (et économiser la batterie sur les portables) ; par la suite, les OS ont directement intégré ce type de code dans leur noyau.
À partir du Pentium 4, l'instruction pause à été créée pour pour diminuer la consommation électrique lors de l'exécution des boucles, sans devoir dépendre des interruptions. Détail amusant, l'opcode correspondant est en fait celui de l'instruction nop avec un préfixe de répétition ; ça n'a donc aucun effet sur les processeurs précédents, mais ça ne déclenche pas d'exception pour cause d'instruction invalide, et les logiciels peuvent du coup utiliser pause sans se préoccuper de la compatibilité.

- l'instruction bsr (dont Ethaniel a parlé sur le Flash Chat récemment) donne le numéro du premier bit à 1 d'un registre, en commençant par le bit de poids fort. Ça semble anecdotique, mais c'est en fait une façon très rapide de calculer la partie entière du logarithme en base 2 ! On peut l'utiliser pour savoir combien de bits sont nécessaires pour stocker une valeur, ou encore de combien de bits il faut décaler pour remplacer une multiplication ou une division par une puissance de 2. bsf fait la même chose en partant du bit de poids faible, mais là j'avoue que je n'ai pas trouvé d'application intéressante.
Posté à
04:53
 par Zerosquare -
Dimanche 07 Mars 2010
x86 vs 68k : les instructions de blocs
Avant de lire cette news, commencez par lire celle juste en-dessous !

Une catégorie d'instructions sympa qui existe sur x86 mais pas sur 68k sont les instructions de blocs. Elles sont grosso modo équivalentes aux fonctions memset(), memcpy(), memcmp() et memchr() de la libc. Pas besoin de s'embêter et de perdre des cycles à le faire à la main !

En fait, en elles-mêmes, les instructions de base n'effectuent qu'une seule itération :
lodsb est l'équivalent de move.b (a0)+, d0
stosb est l'équivalent de move.b d0, (a0)+
movsb est l'équivalent de move.b (a0)+, (a1)+
scasb est l'équivalent de cmp.b (a0)+, d0
cmpsb est l'équivalent de cmp.b (a0)+, (a1)+

Mais on peut leur ajouter des préfixes :
rep permet de répéter l'instruction qui suit n fois
repe (ou repz) fait la même chose que rep, mais la boucle s'arrête avant la fin si le flag Z passe à 0, c'est à dire qu'il n'y a plus égalité
repne (ou repnz) fait la même chose que rep, mais la boucle s'arrête avant la fin si le flag Z passe à 1, c'est à dire qu'il y a égalité

On obtient donc :
rep stosb qui réalise l'équivalent de memset()
rep movsb qui réalise l'équivalent de memcpy()
repe cmpsb qui réalise l'équivalent de memcmp()
repne scasb qui réalise l'équivalent de memchr()

Notez qu'on peut effectuer les mêmes opérations sur 16 ou 32 bits au lieu de 8 bits, en remplaçant le b final par un w ou un d.

Ces instructions utilisent esi et edi comme pointeurs et al/ax/eax comme registre de données. Pour les préfixes rep/repe/repne, ecx contient le nombre de répétitions.

Ça m'a semblé intéressant d'adapter la routine postée dans le blog de Folco sur x86, pour voir si on pouvait tirer profit de ces instructions.

J'ai dû par contre faire un petit changement par rapport à l'original pour que ce soit intéressant : ces instructions sont prévues pour travailler sur des blocs de mémoire de longueur connue à l'avance, par opposition aux chaînes C dont la longueur est inconnue à priori et dont la fin est marquée par un caractère nul. J'ai donc modifié le format de stockage de la table des chaînes pour en faire un tableau de structures :
- adresse de la chaîne (32 bits)
- longueur de la chaîne (32 bits) ; mise à zéro pour indiquer la fin de la table

J'ai également tiré parti du fait que le nombre de séparateurs dans la table est à priori fixe et connu d'avance.

La fonction en question :
; Même fonction que le code de Folco, je répète pas les commentaires :) 
;  
; entrée :	esi : StringTable 
; 		ebp : SeparatorTable 
; 		ebx : RegString 
; 		eax : **NextChar 
; 
; sortie :	edx : numéro de la chaîne, -1 si elle n'a pas été trouvée 
;		*NextChar mis à jour s'il n'était pas nul 
; 
; registres détruits : ecx, edx, esi, edi 
; 
Comparaison_chaines: 
	cld				; mode post-incrémentation 
	xor	edx, edx		; initialise le numéro de la chaîne 
 
Boucle_chaines:	 
	mov	ecx, [esi+4]		; récupère la longueur de la chaîne dans StringTable  
	jecxz	Chaine_non_trouvee	; si nulle, fin de la table -> la chaîne n'a pas été trouvée 
	mov	edi, ebx		; pointeur de comparaison 1 = RefString  
	push	esi			; sauvegarde le pointeur sur StringTable  
	mov	esi, [esi]		; pointeur de comparaison 2 = chaîne indiquée dans StringTable  
	repe	cmpsb			; compare les chaînes 
	pop	esi			; restaure le pointeur sur StringTable  
	je	Verif_separateur	; chaînes identiques -> vérifie le séparateur 
Boucle_chaines_fin: 
	add	esi, 8			; passe à l'entrée suivante de StringTable 
	inc	edx			; incrémente le numéro de la chaîne  
	jmp	Boucle_chaines		; 
Chaine_non_trouvee:			 
	mov	edx, -1			; retourne le code d'erreur 
	ret				; 
 
Verif_separateur: 
	mov	ecx, nb_separateurs	; initialise le nombre de boucles 
	push	eax			; sauvegarde **NextChar 
	mov	al, [edi]		; caractère à rechercher : dernier caractère de RefString 
	push	edi			; sauvegarde le pointeur sur StringTable  
	mov	edi, ebp		; bloc dans lequel rechercher : SeparatorTable  
	repne	scasb			; recherche le caractère 
	pop	edi			; restaure le pointeur sur StringTable  
	pop	eax			; restaure **NextChar 
	jne	Boucle_chaines_fin	; caractère non trouvé -> on passe à la chaîne suivante de StringTable 
	test	eax, eax		; vérifie si **NextChar = NULL 
	jz	Chaine_trouvee		; si non, rien à faire 
	mov	[eax], edi 		; si oui, on enregistre l'adresse du séparateur trouvé  
Chaine_trouvee: 
	ret				; retourne le numéro de la chaîne
Posté à
04:29
 par Zerosquare -
x86 vs 68k : les bases
Comparons les architectures x86 et 68k.

Note : pour la suite, côté 68k je me base sur le 68000, parce que c'est le fondateur de la famille et que c'est le seul que je connais. Côté x86, on devrait prendre le 8086 ou le 80286 pour correspondre à l'historique de la sortie des processeurs, mais je vais me baser sur le 80386 car c'est le premier processeur directement comparable au 68000 (32 bits, accès à la mémoire sans segmentation). Il a aussi des fonctionnalités plus avancées (qu'on retrouve sur les 68020 et suivants) vu qu'il est sorti bien plus tard, mais je n'en parlerai pas ici.

Autant l'avouer franchement (et pourtant j'apprécie ces processeurs), les x86 cumulent un certain nombre de défauts comparé aux 68k :

- 8 registres seulement au lieu de 16

- jeu d'instruction très peu orthogonal : certaines instructions ne peuvent fonctionner qu'avec certains registres

- pas de pré/post incrémentation/décrémentation des registres, à part dans des cas particuliers

- les move n'affectent pas les flags, donc pas question d'écrire des combinaisons move/beq par exemple, il faut intercaler un test supplémentaire

- sauf cas particulier, un seul accès mémoire par instruction

Autant dire que la comparaison des sources 68k vs x86 n'est pas très intéressante la plupart du temps, vu que c'est quasiment toujours la version 68k qui "gagnera".

Il y a pourtant quelques features intéressantes qui existent sur x86 et pas sur 68k. J'essaierai de vous en montrer quelques unes par la suite :)

Pour ceux qui connaissent l'assembleur 68k, voici les différences principales :

- les données sont en little-endian au lieu de big-endian (ça je pense que vous le saviez déjà #hehe# )

- dans l'écriture des instructions, source et cible sont échangées. Donc mov eax, ebx copie ebx dans eax, pas l'inverse !

- byte et word conservent la même signification, mais les entiers 32 bits s'appellent dword (double word).

- les registres 32 bits s'appellent eax, ebx, ecx, edx, esi, edi, ebp et esp (ce dernier étant le pointeur de pile).
On peut accéder aux 16 bits inférieurs sous un autre nom : ax, bx, cx, dx, si, di, bp et sp.
On peut aussi accéder aux 8 bits inférieurs sous les noms al, bl, cl et dl, et aux bits 15 à 8 sous les noms ah, bh, ch et dh.

- par conséquent, il n'y a pas de suffixes .b/.w/.l. La taille de l'instruction est déterminée soit par le nom des registres, soit par la mention explicite byte/word/dword,
soit par le nom de l'instruction elle-même (par exemple, il y a 3 versions de l'instruction stos : stosb (8 bits), stosw (16 bits) et stosd (32 bits)).

- certaines instructions ne travaillent qu'avec un ou plusieurs registres définis d'avance. Dans ce cas, ils ne sont souvent pas mentionnés explicitement dans l'instruction.

- la pré/post incrémentation/décrémentation n'existe pas, sauf pour certaines instructions particulières. Elle s'applique alors à un ou des registres fixes.

- par défaut, les constantes numériques représentent des valeurs immédiates et ne sont donc pas précédées par un dièse. Si on veut indiquer une adresse, il faut entourer la constante par des crochets.

- la notation des adresses se fait en utilisant des crochets et des signes plus. Par exemple, l'équivalent de 4(a0) est [eax+4].

- pas de movea, moveq, etc. Les opcodes existent bien, mais ils s'appellent tous mov, c'est l'assembleur qui se débrouille pour générer le bon.

- les flags ne sont globalement modifiés que par les opérations arithmétiques et logiques, pas les transferts mémoire et autres.

- sauf dans quelques instructions à part, source et destination ne peuvent pas toutes les deux se trouver en mémoire.

- les accès à des adresses mémoires impaires ne provoquent pas d'exception. C'est moins rapide qu'à une adresse alignée, mais ça fonctionne.

- pas de vrai équivalent du movem ; pusha/popa permettent de sauvegarder/restaurer tous les registres d'un coup, mais on ne peut pas en sélectionner une partie seulement.

- il n'y a pas de mode PC relatif.

Voilà pour les bases.
Posté à
03:51
 par Zerosquare -

 RSS  - ©yNBlogs 2004

Login : - Mot de passe :