2010-12-27 8 views
5

Während in einem GNU-Projekt durch einige Quellcode lesen, ich auf dieses Stück Inline-Assembler kam:Hilfe Verständnis DIV-Anweisung in x86-Inline-Assembler

__asm__ (
    "divq %4" 
    : "=a" (q), "=d" (r) 
    : "0" (n0), "1" (n1), "rm" (d) 
); 

Hier werden die Variablen q, r, n0, n1 und d sind 64-Bit-Ganzzahlen. Ich kenne genug Assembly, um den Kern dessen zu verstehen, was das tut, aber es gibt einige Details, über die ich mir nicht sicher bin.

Was ich verstehen:

Wir den Inhalt der RAX-Register durch d teilen, indem die Quotienten in q, und den Rest in r platzieren.

Was verstehe ich nicht

  1. Warum gibt es drei Eingänge hier? Wir müssen nur einen Dividend und einen Divisor eingeben, was könnte also für 3 Eingänge geben?
  2. Ich kann nicht sagen, welche der Eingänge die Dividende ist. Allgemeiner sehe ich nichts wirklich , das in das RAX Register, geladen wird, also wie weiß es, was man durch was teilt?
+1

+1 gut formatierte Frage. Ich mag die Abschnitte "was ich verstehe" und "was ich nicht verstehe". –

Antwort

4

In der Eingangsoperanden-Spezifikation:

: "0" (n0), "1" (n1), "rm" (d) 

Register "0" und "1" sind rax gezwungen und rdx wegen der Ausgangsspezifikation:

: "=a" (q), "=d" (r) 

Und die div Anweisung Familie will der Zähler in RDX:RAX. Der Divisor kann in einem Allzweckregister (nicht anderweitig verwendet - dh nicht RAX oder RDX) oder Speicher sein, der durch die Einschränkung "rm" spezifiziert ist. Die Register RDX, RAX und der Divisor-Operand bilden die 3 Eingänge.

Also wird dies die Division durchführen: n1:n0/d wo n1:n0 ist eine Menge geladen in rdx:rax.

+0

verstehe ich richtig, dass dies verwendet werden kann, um eine 128-Bit-Ganzzahl durch eine 64-Bit-Ganzzahl zu teilen? Ich wusste, dass dies für die 32-Bit-Register-Version möglich war, hätte aber nie gedacht, dass dies auch für die 64-Bit-Version gelten würde. –

+1

@Jens: das ist richtig.Aber denken Sie daran, dass (wie bei den kleineren Operanden-Divisionsoperationen), wenn der Quotient für das Zielregister "rax" zu groß ist, eine Division-Ausnahme auftritt. –

+1

Der schnelle Weg, um für diesen Fall zu testen, besteht einfach darin, sicherzustellen, dass "rdx" kleiner ist als der Divisor, in welchem ​​Fall die Division sicher ist. –

0

Wie Sie richtig beobachten die div Familie auf den festen Registern arbeitet a und d, rax und rdx für divq. Das a-Register erhält seine Eingabe von n0, die zum 0-ten Register aliased ist, nämlich a. n1 ist ein Dummy-Eingang mit Aliasing auf d, wahrscheinlich nur um sicherzustellen, dass dieses Register nicht für andere Zwecke verwendet wird.