2009-12-22 7 views
7

ich 80386 von PC Assembly by paul caurterProblem beim Verständnis mul & IMUL Anweisungen von Assembler

mul source 
  • Wenn der Operand Byte groß, es wird multipliziert mit dem Byte in der AL Register Lernen und Das Ergebnis ist in die 16 Bits von AX gespeichert.

gut.

  • Wenn die Quelle 16-Bit ist, ist es durch das Wort in AX multipliziert wird, und das 32-Bit-Ergebnis wird in DX gespeichert: AX.

Q1: Warum DX: AX? Warum kann es nicht in EAX/EDX gespeichert werden?

imul ist wirklich verwirrend

imul dest, source1 
imul dest, source1, source2 

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

ich Problem habe die Tabelle zu verstehen.

Q2: im zweiten Eintrag der Tabelle. Nochmals, warum DX: AX. Warum nicht EAX oder EDX?

nun folgenden Code-Schnipsel betrachten:

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: Sein sagte previsously dass 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. So ist die Antwort auch in edx gespeichert ist, nicht wahr? im obigen Code haben wir keine EDX berücksichtigt, wir beziehen uns nur auf EAX Wie funktioniert das noch?

Q4: Ich habe ein Problem mit dem Rest aller Einträge in der Tabelle. Worst-Case-Multiplikationsergebnis von zwei n-Bit-Zahlen (n = 8/16/32 Bits) ist 2n Bits. Wie kommt es, dass das Ergebnis von zwei 16/32-Bit-Multiplikationen in einem Register derselben Größe gespeichert wird?

Antwort

7

Q1/Q2: Der x86-Befehlssatz behält seinen 16-Bit-Verlauf bei. Bei einer 16-Bit-Multiplikation wird die Antwort in DX: AX gespeichert. Genau so ist es, denn so war es in 16-Bit-Land.

Q3: Der angezeigte Code weist einen Fehler auf, wenn Sie versuchen, das Quadrat einer Zahl größer als 2^16 zu berechnen, da der Code die hohen 32 Bits des in edx gespeicherten Ergebnisses ignoriert.

Q4: Ich denke, Sie können die Tabelle falsch lesen. 8-Bit-Multiplikationen werden in einem 16-Bit-Ergebnis gespeichert; 16-Bit-Multiplikationen werden in einem 32-Bit-Ergebnis gespeichert; 32-Bit-Multiplikationen werden in einem 64-Bit-Ergebnis gespeichert. Auf welche Zeile beziehen Sie sich konkret?

+1

@ Q3: Ich wusste es. Dies ist der Code aus diesem Buch von Paul Carter. Kannst du mir sagen, wie der Code sein sollte? Ich bin verwirrt, wie man das Ergebnis druckt. – claws

+0

Der angegebene Code ist nur ein Beispiel; Der Text sollte irgendwo erwähnen, dass das Quadrat nicht richtig berechnet wird, wenn die Eingabe außerhalb des erwarteten Bereichs liegt. Da Sie eine 'print_int'-Funktion aufrufen, um eine 32-Bit-Ganzzahl zu drucken, sehen Sie, ob Sie eine 'print_int64'-Funktion zum Drucken einer 64-Bit-Ganzzahl finden können. –

+0

@ Q4: Ja, so soll es sein, aber die Tabelle sagt 16bit Multiplikation ist in 16bit Ergebnis gespeichert. 4. Eintrag: 'dest * = source1' => dest = dest * source1; Ziel ist 16 Bit und Quelle 1 ist 16 Bit. Und es ist der gleiche Fall für alle Tabelleneinträge. sogar der letzte Eintrag source1 & source2 sind 32 bit und dest ist auch 32 bit. – claws

1

Q1/Q2: Ich denke, der Grund ist historisch. Bevor 32-Bit eine Option war, gab es keine eax oder edx. Die 32-Bit-Funktionalität wurde hinzugefügt, um rückwärtskompatibel zu sein.

Q3: Die Bits niedriger Ordnung werden in eax sein. Das sind die einzigen, die dir wichtig sind, es sei denn, es gibt Überlauf in die hohen Bits.

Q4: Definitiv eine ungerade Tabelle. Ich denke, du verstehst es trotzdem.

1

A1:mul war ursprünglich auf den 8086/8088/80186/80286 Prozessoren, die ** (E für erweitert, das heißt 32-bit) Register nicht die E haben.

A2: Siehe A1.

Als meine Arbeit als Programmierer Assembler-Sprache auf die Motorola bewegt Familie vor diesen 32-Bit-680x0 Intels alltäglich geworden ist, werde ich da aufhören :-)

+1

Ich liebe 680x0 Prozessor, ich fand sie leichter zu programmieren als X86 :) – Patrick

4

Oh well ..

Es gibt viele von verschiedenen Variationen der Imul-Anweisung. Und um es noch schlimmer zu machen, funktionieren sie anders, wenn Sie 16-Bit-Code oder 32-Bit-Code schreiben.

Die Variante, auf die Sie gestoßen sind, ist eine 16-Bit-Multiplikation. Es multipliziert das AX-Register mit dem, was Sie als Argument an imul übergeben und speichert das Ergebnis in DX: AX.

Eine 32-Bit-Variante funktioniert wie die 16-Bit-Multiplikation, schreibt aber das Register in EDX: EAX. Um diese Variante zu verwenden, müssen Sie nur ein 32-Bit-Argument verwenden.

Z. B:

; 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 

In 32-Bit-Code, können Sie auch eine IMUL in der Drei-Operanden Form schreiben. Das macht es viel flexibler und einfacher zu arbeiten. In dieser Variante können Sie das Zielregister und die Argumente frei wählen, aber das Ergebnis wird nur 32 Bit lang sein. Diese Variante von imul gibt es nicht für 16-Bit-Code btw ...

+1

können Sie bitte zeigen, wie Sie drucken würden Ergebnis von EDX: EAX '; eine 32-Bit-Multiplikation: '. – claws

2

Q1: Wie andere gesagt, das ist nur für die Rückwärtskompatibilität. Die ursprünglichen mul/imul Anweisungen stammen von 16-Bit x86, die lang gekommen waren, bevor der 32-Bit-x86-Befehlssatz erschien, so dass sie das Ergebnis nicht auf dem eax/edx speichern konnten, da es kein E-Register gab.

Q4: imul reg16, reg/mem/imm16 oder imul reg32, reg/mem/imm32 wird verwendet, wenn Sie nur die unteren 16/32 Bits des Ergebnisses benötigen oder wenn Sie sicherstellen können, dass das Ergebnis nicht überläuft. Wenn zum Beispiel die zwei 32-Bit-Eingänge 1234 mit 567 multipliziert werden, sind die höheren 32 Bits immer 0, so dass EDX nicht wie bei Verwendung von mul von imul mit einem Operanden gespeichert und dann wiederhergestellt werden muss (falls erforderlich).

C-Compiler (wie auch viele andere Sprachen) verwenden oft imul statt mul für beide mit und ohne Vorzeichen Multiplikationen, weil die unteren Bits immer die gleiche für beide Fälle sind, und in C erzeugen multiplizieren zwei Variablen, die eine gleiche Größe Ergebnis (int32xint32 → int32, int16xint16 → int16 ...), was auch der Ergebnisgröße von imul entspricht. Es ist selten, eine Multiplikation zu sehen, bei der die Größe des Ergebnisses größer ist als bei Operanden wie diesem int a; uint64_t p = (uint64_t)a*123;, also ist imul gut für den Zweck. Außerdem können nur die unteren Bits schneller sein als das gesamte Ergebnis. Und die Vielfalt der Befehlsformen macht den ausgegebenen Code effizienter und verbessert die Leistung.Als Ergebnis optimieren moderne CPUs oft für IMUL

Verwandte Themen