867 Stimmen

Was ist der Zweck der LEA-Anweisung?

Für mich ist es einfach nur ein komisches MOV. Was ist sein Zweck und wann sollte ich es verwenden?

8 Stimmen

Siehe auch LEA auf Werte anwenden, die keine Adressen/Zeiger sind? : LEA ist nur ein Shift-and-Add-Befehl. Er wurde wahrscheinlich zum 8086 hinzugefügt, weil die Hardware bereits vorhanden ist, um Adressierungsmodi zu dekodieren und zu berechnen, nicht weil er nur für die Verwendung mit Adressen "gedacht" ist. Denken Sie daran, dass Zeiger in Assembler nur ganze Zahlen sind.

73voto

mmx Punkte 400975

lea ist eine Abkürzung für "effektive Adresse laden". Sie lädt die Adresse der Stelle, auf die der Quelloperand verweist, in den Zieloperanden. Sie können ihn zum Beispiel verwenden, um:

lea ebx, [ebx+eax*8]

zu bewegen ebx Zeiger eax Elemente weiter (in einem 64-Bit/Element-Array) mit einem einzigen Befehl. Im Grunde genommen profitieren Sie von den komplexen Adressierungsmodi, die von der x86-Architektur unterstützt werden, um Zeiger effizient zu bearbeiten.

34voto

David Hoelzer Punkte 15339

Der wichtigste Grund für die Verwendung von LEA über eine MOV ist, wenn Sie mit den Registern, die Sie zur Berechnung der Adresse verwenden, arithmetische Berechnungen durchführen müssen. Sie können praktisch kostenlos eine Art Zeigerarithmetik mit mehreren Registern in Kombination durchführen.

Was wirklich verwirrend ist, ist, dass man normalerweise eine LEA genau wie ein MOV aber Sie dereferenzieren den Speicher nicht wirklich. Mit anderen Worten:

MOV EAX, [ESP+4]

Dadurch wird der Inhalt der ESP+4 zeigt auf in EAX .

LEA EAX, [EBX*8]

Dadurch wird die effektive Adresse verschoben EBX * 8 in EAX, und nicht das, was sich an diesem Ort befindet. Wie Sie sehen können, ist es auch möglich, mit Faktoren von zwei zu multiplizieren (Skalierung), während eine MOV ist auf das Addieren/Subtrahieren beschränkt.

0 Stimmen

Entschuldigung an alle. @big.heart hat mich reingelegt, indem er vor drei Stunden eine Antwort auf diese Frage gegeben hat, so dass sie bei der Durchsuchung meiner Assembly-Fragen als "neu" angezeigt wurde.

3 Stimmen

Warum verwendet die Syntax Klammern, wenn sie keine Speicheradressierung durchführt?

5 Stimmen

@q4w56 Das ist eines dieser Dinge, bei denen die Antwort lautet: "Das macht man eben so." Ich glaube, das ist einer der Gründe, warum es den Menschen so schwer fällt, herauszufinden, was sie tun sollen. LEA tut.

28voto

supercat Punkte 72939

Der 8086 hat eine große Familie von Befehlen, die einen Register-Operanden und eine effektive Adresse akzeptieren, einige Berechnungen durchführen, um den Offset-Teil dieser effektiven Adresse zu berechnen, und einige Operationen durchführen, die das Register und den Speicher betreffen, auf den die berechnete Adresse verweist. Es war recht einfach, einen der Befehle dieser Familie so zu gestalten, dass er sich wie oben beschrieben verhält, nur dass er die eigentliche Speicheroperation überspringt. Daher die Befehle:

mov ax,[bx+si+5]
lea ax,[bx+si+5]

wurden intern fast identisch umgesetzt. Der Unterschied ist ein übersprungener Schritt. Beide Anweisungen funktionieren in etwa so:

temp = fetched immediate operand (5)
temp += bx
temp += si
address_out = temp  (skipped for LEA)
trigger 16-bit read  (skipped for LEA)
temp = data_in  (skipped for LEA)
ax = temp

Ich bin mir nicht ganz sicher, warum Intel diesen Befehl für sinnvoll hielt, aber die Tatsache, dass er billig zu implementieren war, dürfte ein wichtiger Faktor gewesen sein. Ein weiterer Faktor war die Tatsache, dass Intels Assembler die Definition von Symbolen relativ zum BP registrieren. Wenn fnord wurde definiert als ein BP -Relativsymbol (z. B. BP+8 ), könnte man sagen:

mov ax,fnord  ; Equivalent to "mov ax,[BP+8]"

Wenn man etwas verwenden wollte wie stosw Daten in einer BP-relativen Adresse zu speichern, indem sie sagen können

mov ax,0 ; Data to store
mov cx,16 ; Number of words
lea di,fnord
rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

bequemer war als:

mov ax,0 ; Data to store
mov cx,16 ; Number of words
mov di,bp
add di,offset fnord (i.e. 8)
rep movs fnord  ; Address is ignored EXCEPT to note that it's an SS-relative word ptr

Beachten Sie, dass das Vergessen des Welt-"Offsets" dazu führen würde, dass der Inhalt von location [BP+8] und nicht den Wert 8, der zu DI . Ups.

18voto

Kaz Punkte 51547

Der LEA-Befehl (Load Effective Address) ist eine Möglichkeit, die Adresse zu erhalten, die sich aus einem der Speicheradressierungsmodi des Intel-Prozessors ergibt.

Das heißt, wenn wir eine Datenbewegung wie diese haben:

MOV EAX, <MEM-OPERAND>

verschiebt er den Inhalt des angegebenen Speicherplatzes in das Zielregister.

Wenn wir die MOV por LEA dann wird die Adresse des Speicherplatzes auf genau dieselbe Weise von der <MEM-OPERAND> Ausdruck ansprechen. Aber statt des Inhalts der Speicherstelle erhalten wir die Stelle selbst als Ziel.

LEA ist kein spezifischer arithmetischer Befehl, sondern eine Möglichkeit, die effektive Adresse abzufangen, die sich aus einem der Speicheradressierungsmodi des Prozessors ergibt.

Wir können zum Beispiel Folgendes verwenden LEA mit einer einfachen Direktansprache. Es ist überhaupt keine Arithmetik beteiligt:

MOV EAX, GLOBALVAR   ; fetch the value of GLOBALVAR into EAX
LEA EAX, GLOBALVAR   ; fetch the address of GLOBALVAR into EAX.

Dies ist gültig; wir können es an der Linux-Eingabeaufforderung testen:

$ as
LEA 0, %eax
$ objdump -d a.out

a.out:     file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <.text>:
   0:   8d 04 25 00 00 00 00    lea    0x0,%eax

Hier wird weder ein skalierter Wert noch ein Offset hinzugefügt. Null wird nach EAX verschoben. Wir könnten dies auch mit MOV mit einem unmittelbaren Operanden tun.

Dies ist der Grund, warum Menschen, die glauben, dass die Klammern in LEA überflüssig sind, irren sich gewaltig; die Klammern sind nicht LEA Syntax, sondern sind Teil des Adressierungsmodus.

LEA ist auf der Hardware-Ebene real. Der generierte Befehl kodiert den tatsächlichen Adressierungsmodus, und der Prozessor führt ihn bis zum Punkt der Adressberechnung aus. Dann verschiebt er diese Adresse an das Ziel, anstatt eine Speicherreferenz zu erzeugen. (Da die Adressberechnung eines Adressierungsmodus in einem beliebigen anderen Befehl keine Auswirkungen auf CPU-Flags hat, LEA hat keine Auswirkung auf CPU-Flags).

Im Gegensatz zum Laden des Wertes von Adresse Null:

$ as
movl 0, %eax
$ objdump -d a.out | grep mov
   0:   8b 04 25 00 00 00 00    mov    0x0,%eax

Es ist eine sehr ähnliche Kodierung, sehen Sie? Nur die 8d de LEA hat sich geändert in 8b .

Natürlich ist dies LEA Kodierung ist länger als das Verschieben einer unmittelbaren Null in EAX :

$ as
movl $0, %eax
$ objdump -d a.out | grep mov
   0:   b8 00 00 00 00          mov    $0x0,%eax

Es gibt keinen Grund für LEA Ich möchte diese Möglichkeit nicht ausschließen, nur weil es eine kürzere Alternative gibt; sie wird nur auf orthogonale Weise mit den verfügbaren Adressierungsarten kombiniert.

14voto

Thomson Punkte 19262

Wie in den bisherigen Antworten erwähnt, LEA hat den Vorteil, dass er Speicheradressierungsarithmetik ohne Speicherzugriff durchführt und das Rechenergebnis in einem anderen Register speichert als die einfache Form des Additionsbefehls. Der eigentliche Leistungsvorteil besteht darin, dass moderne Prozessoren über eine separate LEA-ALU-Einheit und einen Port für die effektive Adressgenerierung (einschließlich LEA und andere Speicherreferenzadressen), bedeutet dies, dass die arithmetische Operation in LEA und andere normale arithmetische Operationen in der ALU können parallel in einem Kern ausgeführt werden.

In diesem Artikel zur Haswell-Architektur finden Sie einige Details zur LEA-Einheit: http://www.realworldtech.com/haswell-cpu/4/

Ein weiterer wichtiger Punkt, der in anderen Antworten nicht erwähnt wird, ist LEA REG, [MemoryAddress] Befehl ist PIC (positionsunabhängiger Code), der die relative PC-Adresse in diesem Befehl kodiert, um auf MemoryAddress . Dies ist ein Unterschied zu MOV REG, MemoryAddress die eine relative virtuelle Adresse kodiert und in modernen Betriebssystemen (wie z.B. ASLR) relocating/Parcheando erfordert. Also LEA kann verwendet werden, um solche Nicht-PICs in PICs umzuwandeln.

5 Stimmen

Der Teil "separate LEA ALU" ist größtenteils unwahr. Moderne CPUs führen aus lea auf einer oder mehreren der gleichen ALUs, die andere arithmetische Befehle ausführen (aber im Allgemeinen weniger als andere arithmetische Befehle). Die erwähnte Haswell-CPU kann zum Beispiel Folgendes ausführen add ou sub oder die meisten anderen grundlegenden arithmetischen Operationen auf vier verschiedene ALUs, kann aber nur Folgendes ausführen lea auf eine (komplexe lea ) oder zwei (einfache lea ). Noch wichtiger ist, dass diese beiden lea -fähigen ALUs sind lediglich zwei der vier ALUs, die auch andere Befehle ausführen können, so dass es keinen Parallelitätsvorteil gibt, wie behauptet.

3 Stimmen

Der von Ihnen verlinkte Artikel zeigt (korrekterweise), dass LEA auf demselben Port wie eine Integer-ALU (add/sub/boolean) und die Integer-MUL-Einheit in Haswell liegt. (Und Vektor-ALUs einschließlich FP ADD/MUL/FMA). Die einfache LEA-Einheit befindet sich an Port 5, auf dem auch ADD/SUB/whatever, Vektor-Mischungen und andere Dinge laufen. Der einzige Grund, warum ich nicht abstimme, ist, dass Sie auf die Verwendung von RIP-relativer LEA (nur für x86-64) hinweisen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X