Alors que la construction de mon assembleur pour la plate-forme x86 j'ai rencontré quelques problèmes avec le codage de l'instruction JMP
:Comment un JMP relatif (x86) est-il implémenté dans un assembleur?
OPCODE INSTRUCTION SIZE
EB cb JMP rel8 2
E9 cw JMP rel16 4 (because of 0x66 16-bit prefix)
E9 cd JMP rel32 5
...
(de mon site Web d'instructions x86 favori, http://siyobik.info/index.php?module=x86&id=147)
Tous sont par rapport sauts, où la taille de chaque codage (opération + opérande) est dans la troisième colonne.
Maintenant, mon dessin original (et donc la faute à cause de cela) réservait l'espace maximum (5 octets) pour chaque instruction. L'opérande n'est pas encore connu, parce que c'est un saut vers un endroit encore inconnu. J'ai donc implémenté un mécanisme de "réécriture", qui réécrit les opérandes dans l'emplacement correct en mémoire, si l'emplacement du saut est connu, et remplit le reste avec NOP
s. C'est une préoccupation assez sérieuse dans les boucles serrées.
Maintenant, mon problème est la situation suivante:
b: XXX
c: JMP a
e: XXX
...
XXX
d: JMP b
a: XXX (where XXX is any instruction, depending
on the to-be assembled program)
Le problème est que je veux le plus petit encodage possible pour une instruction JMP
(et non remplissage NOP
).
je dois connaître la taille de l'instruction à c
avant que je puisse calculer la distance relative entre a
et b
pour l'opérande à d
. La même chose s'applique pour le JMP
à c
: il doit connaître la taille de d
avant de pouvoir calculer la distance relative entre e
et a
.
Comment les assembleurs existants résolvent-ils ce problème, ou comment le feriez-vous?
C'est ce que je pense qui résout le problème:
encodez toutes les instructions à opcodes entre le
JMP
et sa cible, si cette région contient un opcode de taille variable, utilisez la taille maximale , par exemple5
pour unJMP
. Ensuite, codez leJMP
relatif à sa cible, en choisissant la plus petite taille d'encodage possible (3, 4 ou 5) et calculez la distance. Si un opcode de taille variable est codé, changez tous les opérandes absolus avant, et toutes les instructions relatives qui saute cette instruction codée: ils sont recodés quand leur opérande change pour choisir la plus petite taille possible. Cette méthode est garantie pour se terminer, car les opcodes de taille variable peuvent seulement rétrécir (parce qu'il utilise leur taille maximale).
Je me demande, peut-être ce est une solution sur-ingénierie, c'est la raison pour laquelle je pose cette question.
+1 pour la belle lien de documentation asm –