web-dev-qa-db-fra.com

Utilisation basique des valeurs immédiates et des crochets dans l'assemblage YASM / NASM x86

Supposons que je fasse déclarer ce qui suit:

section .bss
buffer    resb     1

Et ces instructions suivent dans section .text:

mov    al, 5                    ; mov-immediate
mov    [buffer], al             ; store
mov    bl, [buffer]             ; load
mov    cl, buffer               ; mov-immediate?

Ai-je raison de comprendre que bl contiendra la valeur 5 et cl contiendra l'adresse mémoire de la variable buffer?

Je suis confus au sujet des différences entre

  • déplacer un immédiat dans un registre,
  • déplacer un registre dans un immédiat (qu'est-ce qui y entre, les données ou l'adresse?) et
  • déplacement d'un immédiat dans un registre sans les crochets
    • Par exemple, mov cl, buffer contre mov cl, [buffer]

MISE À JOUR: Après avoir lu les réponses, je suppose que le résumé suivant est exact:

  • mov edi, array place l'adresse mémoire de l'index du tableau zéro dans edi. c'est-à-dire l'adresse de l'étiquette.
  • mov byte [edi], 3 met la valeur 3 dans l'index zéro du tableau
  • après add edi, 3, edi contient maintenant l'adresse mémoire du 3ème index du tableau
  • mov al, [array] charge les données à l'index zéro dans al.
  • mov al, [array+3] charge les DONNÉES au troisième index dans al.
  • mov [al], [array] n'est pas valide parce que x86 ne peut pas encoder 2 opérandes de mémoire explicites , et parce que al ne fait que 8 bits et ne peut pas être utilisé même dans un mode d'adressage 16 bits. Référencement du contenu d'un emplacement mémoire. (Modes d'adressage x86)
  • mov array, 3 n'est pas valide, car vous ne pouvez pas dire "Hé, je n'aime pas le décalage auquel array est stocké, alors je l'appellerai 3". Un immédiat ne peut être qu'un opérande source.
  • mov byte [array], 3 met la valeur 3 dans l'index zéro (premier octet) du tableau. Le spécificateur byte est nécessaire pour éviter toute ambiguïté entre byte/Word/dword pour les instructions avec mémoire, opérandes immédiats. Sinon, ce serait une erreur d'assemblage (taille d'opérande ambiguë).

Veuillez mentionner si l'un de ces éléments est faux. (Note de l'éditeur: j'ai corrigé des erreurs/ambiguïtés de syntaxe pour que les valides soient une syntaxe NASM valide. Et lié d'autres questions/réponses pour plus de détails)

29

En effet, votre pensée est correcte, c'est-à-dire que bl contiendra 5 et cl l'adresse mémoire du buffer (en fait le label buffer est une adresse mémoire en soi).


Maintenant, laissez-moi vous expliquer les différences entre les opérations que vous avez mentionnées:

  • déplacer un immédiat dans un registre peut être fait en utilisant mov reg,imm. Ce qui peut prêter à confusion, c'est que les étiquettes, par exemple, buffer sont des valeurs immédiates elles-mêmes qui contiennent une adresse.

  • Vous ne pouvez pas vraiment déplacer un registre dans un registre immédiat, car les valeurs immédiates sont des constantes, comme 2 ou FF1Ah. Ce que vous pouvez faire est de déplacer un registre à l'endroit où la constante pointe. Vous pouvez le faire comme mov [const], reg.

  • Vous pouvez également utiliser un adressage indirect comme mov reg2,[reg1] à condition que reg1 pointe vers un emplacement valide, et il transférera la valeur pointée par reg1 vers reg2.


Alors, mov cl, buffer déplacera adresse du tampon vers cl (qui peut ou non donner l'adresse correcte, puisque cl ne fait qu'un octet de long), alors que mov cl, [buffer] obtiendra la valeur réelle.

Résumé

  • Lorsque vous utilisez [a], vous faites référence à la valeur à l'endroit où pointe a. Par exemple, si a est F5B1, alors [a] fait référence à l'adresse F5B1 dans [~ # ~] ram [~ # ~] .
  • Les libellés sont des adresses, c'est-à-dire des valeurs telles que F5B1.
  • Les valeurs stockées dans les registres n'ont pas à être référencées comme [reg] car les registres n'ont pas d'adresse. En fait, les registres peuvent être considérés comme des valeurs immédiates.
15
byrondrossos

Les crochets fonctionnent essentiellement comme un opérateur de déréférence (par exemple, comme * en C).

Alors, quelque chose comme

mov REG, x

déplace la valeur de x dans REG, alors que

mov REG, [x]

déplace la valeur de l'emplacement mémoire vers lequel pointe x dans REG. Notez que si x est une étiquette, sa valeur est l'adresse de cette étiquette.

Quant à votre question:

Ai-je raison de comprendre que bl contiendra la valeur 5 et cl contiendra l'adresse mémoire du tampon variable?

Oui vous avez raison. Mais attention, puisque CL ne fait que 8 bits de large, il ne contiendra que l'octet le moins significatif de l'adresse de buffer.

21
Job

Vous avez l'idée. Cependant, il y a quelques détails à garder à l'esprit:

  1. Les adresses peuvent et sont généralement supérieures à ce que 8 bits peuvent contenir (cl est 8 bits, cx est 16 bits, ecx est 32 bits, rcx est 64 bits). Ainsi, cl sera probablement différent de l'adresse de la variable buffer. Il n'aura que les 8 bits les moins significatifs de l'adresse.
  2. S'il existe des routines d'interruption ou des threads qui peuvent préempter le code ci-dessus et/ou accéder à buffer, la valeur de bl peut différer de 5. Les routines d'interruption interrompues peuvent en fait affecter n'importe quel registre lorsqu'elles ne parviennent pas à conserver les valeurs de registre.
6
Alexey Frunze

Pour toutes les instructions utilisant des valeurs immédiates comme opérande pour écrire la valeur dans un emplacement RAM (ou pour calculer à l'intérieur), nous devons spécifier le nombre d'octets auxquels nous voulons accéder. Parce que notre assemblage ne peut pas savoir si nous voulons accéder à un seul octet, un Word, ou un doppleword par exemple si la valeur immédiate est inférieure value, comme le montre les instructions suivantes.

array db 0FFh, 0FFh, 0FFh, 0FFh
mov byte [array], 3

résultats:

array db 03h, 0FFh, 0FFh, 0FFh

....

mov Word [array], 3

résultats:

array db 03h, 00h, 0FFh, 0FFh

....

mov dword [array], 3

résultats:

array db 03h, 00h, 00h, 00h

Poignard

3