web-dev-qa-db-fra.com

Le mode 64 bits ne prend pas en charge les instructions Push et POP

NASM renvoie une erreur du type: "instruction non prise en charge en mode 64 bits" et je n'ai pas pu déterminer quoi faire.

L'instruction du sujet est pop ecx et Push ecx instructions. Que puis-je utiliser à leur place ou existe-t-il un autre moyen de résoudre ce problème?

11
Konko

L'idée générale est que vous poussez et ouvrez normalement des registres complets, c'est-à-dire des registres 64 bits en mode 64 bits. La taille d'opérande par défaut de Push est 64 bits et la taille d'opérande 32 bits n'est pas disponible. Chaque instruction Push envoie-t-elle un multiple de 8 octets sur x64? (oui, sauf si vous utilisez spécifiquement un push 16 bits, mais 32 bits n'est pas disponible).

Vous ne pouvez pas pousser un registre 32 bits en mode 64 bits; à la place, vous pouvez pousser et afficher le registre 64 bits complet qui contient la valeur 32 bits que vous souhaitez, c'est donc Push rax au lieu de Push eax. Il en va de même pour les références de mémoire - vous pouvez Push qword ptr[rax], mais non Push dword ptr[rax].

Mais : même en mode 64 bits, vous pouvez toujours pousser:

  • Signe Immediates 8 ou 32 bits étendu à 64; ceci est généralement géré automatiquement par votre assembleur comme une optimisation (si vous faites Push 1 il le codera avec l'encodage le plus compact, qui sera 6A01, c'est-à-dire avec un imm8 opérande). C'est toujours un Push 64 bits, sauf si vous spécifiez explicitement Push Word 1 , quelle que soit la largeur de l'immédiat choisi par l'assembleur.

  • les registres de segments fs et gs mais pas les cs, ds , es, ss registres (qui ne sont pas importants en mode 64 bits et ne peuvent être lus qu'avec mov , pas Push, libérant ces opcode Push/pop pour une utilisation future potentielle).

    Par exception, les registres de segments sont soit zéro - étendus ou poussés sur la pile avec un déplacement de 16 bits (c'est-à-dire que les 48 autres bits de la pile sont non modifié); ce n'est pas vraiment un gros problème, car pop fs et pop gs jetez simplement ces bits supplémentaires.

Vous pouvez émuler un Push imm64 avec Push low32/mov dword [rsp+4], high32. Ou avec mov r64, imm64/Push r64; mov pour enregistrer (pas la mémoire) est la seule instruction x86-64 qui peut prendre un 64 bits immédiat.


Avec une taille d'opérande 16 bits (un 66h prefix), vous pouvez faire un Push 16 bits qui ajuste RSP par 2 au lieu de 8. Mais normalement ne le faites pas car cela désalignera la pile jusqu'à ce que vous fassiez un pop 16 bits ou que vous le corrigiez.

  • Registres 16 bits (Push ax) et les références de mémoire (Push Word ptr[rax]);
  • Extension de signe 8 bits ou immédiat 16 bits.

Les registres 8 bits ne peuvent être poussés dans aucun mode (sauf dans le cadre d'un registre plus large), et 32 ​​bits n'est pas disponible en mode 64 bits, même avec un REX.W=0 préfixe .

18
Matteo Italia