Question

Je suis en train d'apprendre ensemble (donc garder avec moi) et je reçois une erreur de compilation sur cette ligne:

mov byte [t_last], [t_cur]

L'erreur est

error: invalid combination of opcode and operands

Je soupçonne que la cause de cette erreur est simplement que ce ne est pas possible pour une instruction mov de se déplacer entre deux adresses de mémoire, mais une demi-heure de googler et je ne l'ai pas été en mesure de confirmer - est-ce le cas?

En outre, en supposant que je ne me trompe pas cela signifie que je dois utiliser un registre comme un point intermédiaire pour la mémoire de la copie:

mov cl, [t_cur]
mov [t_last], cl

Quel est le registre recommandé d'utiliser (ou devrais-je utiliser la pile à la place)?

Était-ce utile?

La solution

Votre soupçon est correcte, vous ne pouvez pas passer de la mémoire à la mémoire.

Tout registre à usage général fera. Rappelez-vous de pousser le registre si vous n'êtes pas sûr de ce qu'il ya dedans et de le restaurer une fois fait.

Autres conseils

Il est vraiment simple 16 bits, il suffit de ce qui suit:

     push     di
     push     si
     push     cx
     mov      cx,(number of bytes to move)
     lea      di,(destination address)
     lea      si,(source address)
     rep      movsb
     pop      cx
     pop      si
     pop      di

Note: les & pops sont poussées neceessary si vous avez besoin pour enregistrer le contenu des registres

.

Il y a aussi une commande MOVS à partir des données de la mémoire en mouvement à la mémoire:

MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS

Il est techniquement possible de passer de la mémoire à la mémoire.

Essayez d'utiliser MOVS (chaîne de déplacement), et réglage [E] SI et [E] DI , selon que vous voulez transférer l'octet (s), mot (s), etc.

mov si, t_cur    ; Load SI with address of 't_cur'
mov di, t_last   ; Load DI with address of 't_last'
movsb            ; Move byte from [SI] to [DI]

; Some dummy data
t_cur    db 0x9a ; DB tells NASM that we want to declare a byte
t_last   db 0x7f ; (See above)

Ceci est moins efficace que l'utilisation d'une charge normale + magasin avec un registre temporaire, mais il ne fait la copie réelle avec une seule instruction.

Voilà comment doit être utilisé MOVS , et comment cela fonctionne: https://www.felixcloutier.com/x86/movs:movsb: movsw: movsd: movsq

Il est normalement utilisé uniquement avec un préfixe de rep pour les copies de bloc, et non pour un seul élément. (Unités centrales modernes ont microcode assez efficace pour rep movsb que près de la vitesse d'une boucle en utilisant des instructions de chargement / stockage de vecteur AVX.)

C'est exact, le code de la machine x86 ne peut pas coder une instruction avec deux explicite opérandes de mémoire (adresses arbitraires spécifiées dans [])

  

Quel est le registre recommandé

Tout registre que vous ne avez pas besoin de sauvegarder / restaurer.

Dans toutes les conventions d'appel traditionnels 32 bits et 64 bits, EAX, ECX et EDX sont appel maltraité par, donc AL, CL, et DL sont de bons choix. Pour un octet ou mot copie, vous voulez généralement une charge movzx dans un registre 32 bits, un 8 bits ou 16 bits magasin. Cela permet d'éviter une fausse dépendance à l'ancienne valeur du registre. Utiliser uniquement une étroite 16 ou 8 bits charge mov si vous activement voulez pour se fondre dans les bits de poids faible d'une autre valeur. Le movzx x86 est l'analogue d'instructions comme ARM ldrb.

    movzx   ecx,  byte [rdi]       ; load CL, zero-extending into RCX
    mov    [rdi+10], cl

En mode 64 bits, SIL, DIL, R8b, R9b et ainsi de suite sont aussi beaux choix, mais exigent un préfixe REX en code machine pour le magasin donc il y a une raison mineure taille de code pour les éviter.

En général, évitez d'écrire AH, BH, CH ou DH pour des raisons de performance, à moins que vous avez lu et compris les liens suivants et les fausses dépendances ou des stalles de fusion registre partiel ne vont pas être un problème ou tout se dans votre code.


  

(ou devrais-je utiliser la pile à la place)?

Tout d'abord, vous ne pouvez pas appuyer sur un seul octet du tout, donc il n'y a aucun moyen que vous pourriez faire un magasin octet charge / octet de la pile. Pour un mot, dword ou QWORD (selon le mode CPU), vous pouvez push [src] / pop [dst], mais c'est beaucoup plus lent que la copie par l'intermédiaire d'un registre. Il introduit un temps d'attente magasin de transfert magasin / recharge supplémentaire avant que les données peuvent être lues à partir de la destination finale, et prend plus UOP.

A moins quelque part sur la pile la destination souhaitée et vous ne pouvez pas optimiser la variable locale dans un registre, auquel cas push [src] est très bien pour le copier là et allouer de l'espace de pile pour elle.

https://agner.org/optimize/ et d'autres liens de performance x86 dans le wiki tag x86

Je veux juste discuter « barrière de mémoire » avec vous. Dans le code c

a = b;//Take data from b and puts it in a

serait assemblé à

mov %eax, b # suppose %eax is used as the temp
mov a, %eax

Le système ne peut pas garantir l'atomicité de la mission. Voilà pourquoi nous avons besoin d'un rmb (Barrière lecture)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top