Welche 2-Komplement-Integer-Operationen können verwendet werden, ohne hohe Bits in den Eingängen auf Null zu setzen, wenn nur der niedrige Teil des Ergebnisses gewünscht wird?

Bei der Assembly-Programmierung ist es üblich, aus den niedrigen Bits eines Registers etwas zu berechnen, bei dem nicht garantiert ist, dass die anderen Bits auf Null gesetzt sind. In höheren Sprachen wie C werden die Eingaben einfach auf die kleine Größe gebracht, und der Compiler entscheidet, ob die oberen Bits jeder Eingabe einzeln auf Null gesetzt werden müssen oder ob die oberen Bits des Ergebnisses nach dem abgeschnitten werden Tatsache

Dies ist aus verschiedenen Gründen besonders häufig bei x86-64 (auch bekannt als AMD64).1, von denen einige in anderen ISAs vorhanden sind.

Ich werde 64bit x86 als Beispiel verwenden, aber die Absicht ist, nach / discussion @ zu frage 2's Ergänzung und vorzeichenlose binäre Arithmetik im Allgemeinen, daalle modernen CPUs benutzen es. (Beachten Sie, dass C und C ++ nicht das Zweierkomplement garantieren.4, und dieser signierte Überlauf ist undefiniertes Verhalten.)

tellen Sie sich als Beispiel eine einfache Funktion vor, die zu einem @ kompiliert werden kanLEA Anweisun2. (In der x86-64 SysV (Linux) ABI3, die ersten beiden Funktionsargumente sind inrdi undrsi, mit der Rückkehr inrax. int ist ein 32-Bit-Typ.)

; int intfunc(int a, int b) { return a + b*4 + 3; }
intfunc:
    lea  eax,  [edi + esi*4 + 3]  ; the obvious choice, but gcc can do better
    ret

gcc weiß, dass die Addition selbst von Ganzzahlen mit negativem Vorzeichen nur von rechts nach links erfolgt, sodass die oberen Bits der Eingaben keinen Einfluss darauf haben, was in @ eingegeben wireax. Also,it speichert ein Anweisungsbyte und verwendet lea eax, [rdi + rsi*4 + 3]

Welche anderen Operationen haben diese Eigenschaft der Low-Bits des Ergebnisses unabhängig von den High-Bits der Eingänge?

nd warum funktioniert e

Fußnoten

1 Warum kommt dies häufig für x86-64: x86-64 verfügt über Befehle variabler Länge, wobei ein zusätzliches Präfixbyte die Operandengröße ändert (von 32 auf 64 oder 16), sodass das Speichern eines Bytes häufig in Befehlen möglich ist, die ansonsten mit derselben Geschwindigkeit ausgeführt werden. Es hat auch falsche Abhängigkeiten (AMD / P4 / Silvermont) beim Schreiben der niedrigen 8b oder 16b eines Registers (oder einen Stillstand beim späteren Lesen des vollständigen Registers (Intel vor IvB)): Aus historischen Gründen, schreibt nur den Rest des 64b-Registers in die 32b-Unterregister Null. Nahezu alle Arithmetik- und Logikfunktionen können für die niedrigen 8-, 16- oder 32-Bit-Werte sowie für die vollständigen 64-Bit-Werte von Mehrzweckregistern verwendet werden. Ganzzahlige Vektoranweisungen sind auch ziemlich unorthogonal, wobei einige Operationen für einige Elementgrößen nicht verfügbar sind.

Im Gegensatz zu x86-32 übergibt der ABI außerdem Funktionsargumente in Registern, und die oberen Bits müssen für schmale Typen nicht Null sein.

2 LEA: Wie bei anderen Anweisungen ist die Standardoperandengröße von LEA ist 32 Bit, aber die Standardadressgröße ist 64 Bit. Ein Präfixbyte in Operandengröße 0x66 oderREX.W) kann die Ausgabeoperandengröße auf 16 oder 64 Bit setzen. Ein Adressgrößen-Präfixbyte 0x67) kann die Adressgröße auf 32 Bit (im 64-Bit-Modus) oder 16 Bit (im 32-Bit-Modus) reduzieren. Also im 64-Bit-Modus,lea eax, [edx+esi] nimmt ein Byte mehr alslea eax, [rdx+rsi].

Es ist möglich, @ zu tlea rax, [edx+esi], aber die Adresse wird immer noch nur mit 32 Bit berechnet (ein Übertrag setzt nicht Bit 32 vonrax). Sie erhalten identische Ergebnisse mitlea eax, [rdx+rsi] ist zwei Bytes kürzer. Daher ist das Adressgrößenpräfix bei @ niemals nützlicLEA, wie die Kommentare in Disassembler-Ausgabe von Agner Fog's ausgezeichnetem Disassembler-Objekt warnen.

3 x86 ABI: Der Anrufer does muss den oberen Teil der 64-Bit-Register auf Null setzen (oder durch Vorzeichen erweitern), die zum Übergeben oder Zurückgeben kleinerer Typen nach Wert verwendet werden. Ein Aufrufer, der den Rückgabewert als Array-Index verwenden wollte, musste ihn signieren und erweitern (mit @movzx rax, eax, oder die Spezialanweisung für eaxcdqe. (nicht zu verwechseln mitcdq, welches Zeichen erweiterteaxinedx:eax z.B. einrichten füridiv.))

Dies bedeutet, dass eine Funktion @ zurückgibunsigned int kann seinen Rückgabewert in einem temporären 64bit in @ berechnrax und kein @ erforderlimov eax, eax zur Nullstellung der oberen Bits vonrax. Diese Entwurfsentscheidung funktioniert in den meisten Fällen gut: Oft benötigt der Aufrufer keine zusätzlichen Anweisungen, um die undefinierten Bits in der oberen Hälfte von @ zu ignoriererax.

4 C und C ++

C und C ++ tun spezifischnich erfordert zwei Komplement-Ganzzahlen mit binären Vorzeichen (außer C ++std::atomic types). Das eigene Komplement und Vorzeichen / Größe sind ebenfalls erlaubt, so fürvölli portable C, diese Tricks sind nur mit @ nützliunsigned Typen. Offensichtlich bedeutet für vorzeichenbehaftete Operationen ein gesetztes Vorzeichenbit in Vorzeichen- / Betragsdarstellung, dass die anderen Bits zum Beispiel nicht addiert, sondern subtrahiert werden. Ich habe die Logik für die eigene Ergänzung nicht durchgearbeitet

Jedoch, Bit-Hacks Das nur mit Zweierkomplement arbeiten sindweit verbreite, denn in der Praxis kümmert sich niemand um etwas anderes. Viele Dinge, die mit dem Zweierkomplement funktionieren, sollten auch mit dem eigenen Komplement funktionieren, da das Vorzeichenbit die Interpretation der anderen Bits immer noch nicht ändert: Es hat nur einen Wert von - (2N -1) (anstelle von 2N). Die Darstellung des Vorzeichens / der Größe hat diese Eigenschaft nicht: Der Stellenwert jedes Bits ist je nach Vorzeichenbit positiv oder negativ.

Beachten Sie auch, dass C-Compiler diesen signierten Überlauf annehmen dürfen passiert nie, weil es undefiniertes Verhalten ist. So kann z.B.compiler können und wollen davon ausgehen,(x+1) < x ist immer falsch. Dies macht das Erkennen eines signierten Überlaufs in C ziemlich unpraktisch.Beachten Sie, dass der Unterschied zwischen vorzeichenlosem Wraparound (Übertrag) und vorzeichenbehaftetem Überlauf.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage