Assemblée: entre deux adresses mobiles de mémoire
-
18-09-2019 - |
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)?
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 []
)
- Pourquoi MOVL pas de mémoire à mémoire autorisée?
- Quelles instructions x86 prennent deux (ou plus) opérandes de mémoire?
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.
- Pourquoi ne pas utiliser GCC registres partiel
- Comment faire exactement registres partiels sur Haswell effectuer / Skylake? L'écriture AL semble avoir une fausse dépendance à l'égard RAX et AH est incompatible
(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)