2009-12-22 6 views
7

J'apprends 80386 de PC Assembly by paul caurterdans la compréhension des instructions et mul IMUL de langue Assemblée

mul source 
  • Si l'opérande est l'octet de taille, il est multiplié par l'octet dans le registre AL et le résultat est stocké dans les 16 bits de AX.

fine.

  • Si la source est de 16 bits, il est multiplié par le mot AX et le résultat 32 bits est stocké dans DX: AX.

Q1: Pourquoi DX: AX? Pourquoi ne peut-il pas stocker dans EAX/EDX?

imul est vraiment déroutant

imul dest, source1 
imul dest, source1, source2 

alt text http://img697.imageshack.us/img697/8976/imul.gif

J'ai problème dans la compréhension de la table.

Q2: dans la deuxième entrée de la table. Encore une fois, pourquoi DX: AX. Pourquoi pas EAX ou EDX?

code suivant maintenant considérer extrait:

imul eax ; edx:eax = eax * eax 
mov ebx, eax ; save answer in ebx 
mov eax, square_msg ; square_msg db "Square of input is ", 0 
call print_string ; prints the string eax 
mov eax, ebx 
call print_int ; prints the int stored in eax 
call print_nl ; prints new line 

Q3: Son dit que previsously The notation EDX:EAX means to think of the EDX and EAX registers as one 64 bit register with the upper 32 bits in EDX and the lower bits in EAX. Donc, la réponse est également stockée dans EDX, non? Dans le code ci-dessus, nous n'avons pas considéré EDX, nous faisons simplement référence à EAX Comment cela fonctionne-t-il encore?

Q4: J'ai un problème avec le reste de toutes les entrées de la table. le pire résultat de multiplication de deux nombres de n bits (n = 8/16/32 bits) est de 2n bits. Comment se fait-il que le stockage de deux résultats de multiplication 16/32 bits aboutisse à un registre de même taille?

Répondre

7

Q1/Q2: L'ensemble d'instructions x86 conserve son historique de 16 bits. Lorsque vous effectuez une multiplication 16 bits, la réponse est stockée dans DX: AX. C'est juste comme ça, parce que c'était comme ça en 16 bits. Q3: Le code que vous avez montré a un bug si vous essayez de calculer le carré d'un nombre supérieur à 2^16, car le code ignore les 32 bits élevés du résultat stocké dans edx. Q4: Je pense que vous pourriez mal interpréter la table. Les multiplications à 8 bits sont stockées dans un résultat de 16 bits; Les multiplications 16 bits sont stockées dans un résultat de 32 bits; Les multiplications 32 bits sont stockées dans un résultat 64 bits. De quelle ligne parlez-vous spécifiquement?

+1

@ Q3: Je le savais. c'est le code de ce livre de paul carter. Pouvez-vous me dire comment le code devrait être? Je suis confus comment imprimer le résultat. – claws

+0

Le code tel que donné est juste un exemple; le texte doit mentionner quelque part qu'il ne calculera pas correctement le carré si l'entrée est en dehors de la plage attendue. Puisque vous appelez une fonction 'print_int' pour imprimer un entier de 32 bits, voyez si vous pouvez trouver une fonction' print_int64' pour imprimer un entier de 64 bits. –

+0

@ Q4: Ouais, c'est comme ça que ça se passe mais la table dit que la multiplication 16 bits est stockée en résultat 16bit. 4ème entrée: 'dest * = source1' => dest = dest * source1; dest est 16bit et source1 est 16bit. Et c'est le même cas pour toutes les entrées de la table. même la dernière entrée source1 & source2 est de 32 bits et dest est également de 32 bits. – claws

1

Q1/Q2: Je pense que la raison est historique. Avant l'option 32 bits, il n'y avait pas eax ou edx. La fonctionnalité 32 bits a été ajoutée pour être compatible inverse.

Q3: Les bits de poids faible vont être dans eax. Ce sont les seuls qui vous tiennent à cœur, à moins qu'il y ait débordement dans les bits élevés.

Q4: Définitivement une table impaire. Je pense que vous l'avez compris.

1

A1:mul était présent à l'origine sur les 8086/8088/80186/80286 processeurs, qui n'ont pas les registres E ** (E eXtended, à savoir 32 bits).

A2: Voir A1.

Comme mon travail en tant que programmeur de langage assembleur déplacé vers le Motorola 680x0 famille avant les 32 bits Intels est devenu monnaie courante, je vais arrêter là :-)

+1

J'aimais le processeur 680x0, je les ai trouvés plus facile à programmer que X86 :) – Patrick

4

Oh bien ..

Il y a beaucoup de différentes variations de l'instruction imul. Et pour empirer les choses, ils fonctionnent différemment si vous écrivez un code de 16 bits par rapport au code de 32 bits.

La variante sur laquelle vous avez trébuché est une multiplication 16 bits. Il multiplie le registre AX avec tout ce que vous passez comme argument pour imul et stocke le résultat dans DX: AX. Une variante de 32 bits fonctionne comme la multiplication 16 bits mais écrit le registre dans EDX: EAX. Pour utiliser cette variante, tout ce que vous avez à faire est d'utiliser un argument de 32 bits.

par exemple:

; a 16 bit multiplication: 
    mov ax, factor1 
    mov bx, factor2 
    imul bx ; result in DX:AX 

    ; a 32 bit multiplication: 
    mov eax, factor1 
    mov ebx, factor2 
    imul ebx ; result in EDX:EAX 

Dans 32 bit code, vous pouvez également écrire un imul dans les trois sous forme d'opérande. Cela le rend beaucoup plus flexible et plus facile à travailler. Dans cette variante, vous pouvez choisir librement le registre de destination et les arguments, mais le résultat ne sera que de 32 bits. Cette variante de imul n'existe pas pour code 16 bits btw ...

mov eax, factor1 
    mov ebx, factor2 
    imul ecx, eax, ebx ; result in ecx 
+1

pouvez-vous s'il vous plaît montrer comment voulez-vous imprimer le résultat d'EDX: EAX '; une multiplication 32 bits: – claws

2

Q1: Comme d'autres ont dit, c'est juste pour la compatibilité descendante. Les instructions mul/imul d'origine proviennent du x86 16 bits qui était arrivé long avant l'apparition de l'ensemble d'instructions x86 32 bits, de sorte qu'ils ne pouvaient pas stocker le résultat dans eax/edx car il n'y avait pas de registre électronique.

Q4: imul reg16, reg/mem/imm16 ou imul reg32, reg/mem/imm32 est utilisé lorsque vous avez seulement besoin des 16/32 bits inférieurs du résultat ou lorsque vous pouvez vous assurer que le résultat ne déborde pas. Par exemple, en multipliant les deux nombres 32 bits 1234 par 567, les 32 bits supérieurs sont toujours 0, il n'est donc pas nécessaire d'enregistrer et de restaurer (si nécessaire) edx comme lorsque vous utilisez mul de imul avec un opérande.

compilateurs C (ainsi que beaucoup d'autres langues) utilisent souvent imul au lieu de mul pour les deux signées et multiplications non signés parce que les bits inférieurs sont toujours les mêmes pour les deux cas, et en C multiplier les deux variables génèrent une même taille résultat (int32xint32 → int32, int16xint16 → int16 ...) qui est également comme la taille de résultat de imul. Il est rare de voir une multiplication où la taille du résultat est plus grande que les opérandes int a; uint64_t p = (uint64_t)a*123;, donc imul est bon pour le but. En plus de faire seulement les bits inférieurs peuvent être plus rapides que d'obtenir le résultat entier. Et la variété des formulaires d'instruction imul rend le code émis plus efficace et améliore les performances.En conséquence, les processeurs modernes optimisent souvent pour imul au lieu de mul

Questions connexes