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.

1012voto

I. J. Kennedy Punkte 23203

Wie bereits von anderen erwähnt, wird LEA (load effective address) oft als "Trick" für bestimmte Berechnungen verwendet, aber das ist nicht ihr Hauptzweck. Der x86-Befehlssatz wurde entwickelt, um Hochsprachen wie Pascal und C zu unterstützen, in denen Arrays - insbesondere Arrays von Ints oder kleinen Structs - üblich sind. Betrachten wir zum Beispiel eine Struktur, die (x, y)-Koordinaten darstellt:

struct Point
{
     int xcoord;
     int ycoord;
};

Stellen Sie sich nun eine Aussage wie diese vor:

int y = points[i].ycoord;

donde points[] ist ein Array aus Point . Angenommen, die Basis des Arrays befindet sich bereits in EBX und variabel i ist in EAX y xcoord y ycoord sind jeweils 32 Bit (also ycoord an einem Offset von 4 Bytes in der Struktur steht), kann diese Anweisung kompiliert werden zu:

MOV EDX, [EBX + 8*EAX + 4]    ; right side is "effective address"

was zu einer y en EDX . Der Skalierungsfaktor von 8 ist darauf zurückzuführen, dass jede Point hat eine Größe von 8 Byte. Betrachten wir nun denselben Ausdruck mit dem "Adresse von"-Operator &:

int *p = &points[i].ycoord;

In diesem Fall wollen Sie nicht, dass der Wert von ycoord sondern seine Adresse. Das ist der Ort LEA (ladungswirksame Adresse) eintritt. Anstelle einer MOV kann der Compiler Folgendes erzeugen

LEA ESI, [EBX + 8*EAX + 4]

die die Adresse in ESI .

159 Stimmen

Wäre es nicht sauberer gewesen, die mov Anleitung und lassen Sie die Klammern weg? MOV EDX, EBX + 8*EAX + 4

26 Stimmen

@imacake Indem Sie LEA durch ein spezielles MOV ersetzen, halten Sie die Syntax sauber: []-Klammern sind immer das Äquivalent zur Dereferenzierung eines Zeigers in C. Ohne Klammern haben Sie es immer mit dem Zeiger selbst zu tun.

1 Stimmen

@Natan Hey ASM ist sowieso nie trivial! :D

648voto

Frank Krueger Punkte 67044

Desde el "Zen der Montage" von Abrash:

LEA ist die einzige Anweisung, die Berechnungen zur Speicheradressierung durchführt, aber den Speicher nicht tatsächlich adressiert. LEA akzeptiert einen Standard-Speicheradressierungsoperanden, tut aber nichts weiter, als den berechneten Speicher-Offset in dem angegebenen Register zu speichern, das ein beliebiges Allzweckregister sein kann.

Was bedeutet das für uns? Zwei Dinge, die ADD nicht zur Verfügung stellt:

  1. die Fähigkeit, Additionen mit zwei oder drei Operanden durchzuführen, und
  2. die Möglichkeit, das Ergebnis zu speichern in jede Register; nicht nur einen der Quelloperanden.

Und LEA ändert die Flaggen nicht.

Beispiele

  • LEA EAX, [ EAX + EBX + 1234567 ] errechnet EAX + EBX + 1234567 (das sind drei Operanden)
  • LEA EAX, [ EBX + ECX ] errechnet EBX + ECX ohne diese mit dem Ergebnis zu überschreiben.
  • Multiplikation mit einer Konstante (mit zwei, drei, fünf oder neun), wenn man sie wie folgt verwendet LEA EAX, [ EBX + N * EBX ] (N kann 1,2,4,8 sein).

Ein anderer Anwendungsfall ist praktisch in Schleifen: Der Unterschied zwischen LEA EAX, [ EAX + 1 ] y INC EAX ist, dass die letzteren Änderungen EFLAGS aber die erste nicht; dadurch bleibt die CMP Zustand.

46 Stimmen

@AbidRahmanK einige Beispiele: LEA EAX, [ EAX + EBX + 1234567 ] berechnet die Summe von EAX , EBX y 1234567 (das sind drei Operanden). LEA EAX, [ EBX + ECX ] errechnet EBX + ECX ohne entweder mit dem Ergebnis überschreiben. Die dritte Sache LEA verwendet wird (von Frank nicht aufgeführt), ist Multiplikation mit Konstante (durch zwei, drei, fünf oder neun), wenn Sie es wie folgt verwenden LEA EAX, [ EBX + N * EBX ] ( N kann 1,2,4,8 sein). Ein anderer Anwendungsfall ist praktisch in Schleifen: der Unterschied zwischen LEA EAX, [ EAX + 1 ] y INC EAX ist, dass die letzteren Änderungen EFLAGS aber die erste nicht; dadurch bleibt die CMP Staat

0 Stimmen

@FrankH. Ich verstehe es immer noch nicht, also lädt es einen Zeiger auf etwas anderes?

6 Stimmen

@ripDaddy69 ja, in gewisser Weise - wenn Sie mit "laden" "die Adressberechnung/Zeigerarithmetik durchführen" meinen. Das tut es nicht auf den Speicher zugreifen (d.h. keine "Dereferenzierung" des Zeigers, wie es in der C-Programmierung heißen würde).

132voto

Angus Lee Punkte 1386

Ein weiteres wichtiges Merkmal der LEA Anweisung ist, dass sie die Konditionscodes nicht ändert, wie zum Beispiel CF y ZF bei der Berechnung der Adresse durch arithmetische Befehle wie ADD o MUL tut. Diese Funktion verringert die Abhängigkeit zwischen den Anweisungen und schafft somit Raum für weitere Optimierungen durch den Compiler oder den Hardware-Scheduler.

2 Stimmen

Ja, lea ist manchmal nützlich für den Compiler (oder den menschlichen Programmierer), um Berechnungen durchzuführen, ohne ein Flag-Ergebnis zu verfälschen. Aber lea nicht schneller ist als add . Die meisten x86-Befehle schreiben Flags. Leistungsstarke x86-Implementierungen müssen EFLAGS umbenennen oder anderweitig vermeiden die Gefahr des Schreibens nach dem Schreiben Damit normaler Code schnell läuft, sind Anweisungen, die das Schreiben von Flags vermeiden, deshalb nicht besser. ( teilweise Flaggenmaterial kann Probleme verursachen, siehe INC-Anweisung gegenüber ADD 1: Ist das wichtig? )

2 Stimmen

@PeterCordes : Ich spreche das hier nur ungern an, aber - bin ich der einzige, der dieses neue [x86-lea]-Tag für überflüssig und unnötig hält?

3 Stimmen

@MichaelPetch: Ja, ich denke, es ist zu spezifisch. Es scheint Anfänger zu verwirren, die die Maschinensprache nicht verstehen, und dass alles (einschließlich Zeiger) nur Bits/Bytes/Integer sind, daher gibt es viele Fragen dazu mit einer großen Anzahl von Stimmen. Aber ein Tag dafür zu haben, impliziert, dass es Platz für eine unbegrenzte Anzahl zukünftiger Fragen gibt, während es in Wirklichkeit nur 2 oder 3 Fragen gibt, die nicht nur Duplikate sind. (Was ist das? Wie verwendet man es zum Multiplizieren von ganzen Zahlen? und wie läuft es intern auf AGUs vs. ALUs und mit welcher Latenz / welchem Durchsatz. Und vielleicht ist es der "beabsichtigte" Zweck)

113voto

hdante Punkte 6926

Trotz aller Erklärungen ist LEA eine arithmetische Operation:

LEA Rt, [Rs1+a*Rs2+b] =>  Rt = Rs1 + a*Rs2 + b

Es ist nur so, dass der Name extrem dumm ist für eine Shift+Add Operation. Der Grund dafür wurde bereits in den am besten bewerteten Antworten erklärt (d.h. er wurde entwickelt, um High-Level-Speicherreferenzen direkt abzubilden).

11 Stimmen

Und dass die Arithmetik von der Hardware für die Adressberechnung durchgeführt wird.

38 Stimmen

@BenVoigt Das habe ich immer gesagt, weil ich ein alter Knacker bin :-) Traditionell haben die x86-CPUs die Adressierungseinheiten dafür verwendet, das stimmt. Aber die "Trennung" ist heutzutage sehr unscharf geworden. Einige CPUs haben nicht mehr engagiert AGUs überhaupt, andere haben sich dafür entschieden, nicht auszuführen LEA auf den AGUs, sondern auf den gewöhnlichen Integer-ALUs. Heutzutage muss man die CPU-Spezifikationen sehr genau lesen, um herauszufinden, "wo etwas läuft" ...

2 Stimmen

@FrankH.: Out-of-Order-CPUs lassen LEA typischerweise auf ALUs laufen, während einige In-Order-CPUs (wie Atom) es manchmal auf AGUs laufen lassen (weil sie nicht damit beschäftigt sein können, einen Speicherzugriff zu verarbeiten).

93voto

GJ. Punkte 10524

Vielleicht nur eine weitere Sache über LEA-Unterricht. Sie können LEA auch für die schnelle Multiplikation von Registern mit 3, 5 oder 9 verwenden.

LEA EAX, [EAX * 2 + EAX]   ;EAX = EAX * 3
LEA EAX, [EAX * 4 + EAX]   ;EAX = EAX * 5
LEA EAX, [EAX * 8 + EAX]   ;EAX = EAX * 9

16 Stimmen

+1 für den Trick. Aber ich möchte eine Frage stellen (kann dumm sein), warum nicht direkt mit drei multiplizieren wie diese LEA EAX, [EAX*3] ?

16 Stimmen

@Abid Rahman K: Es gibt keinen solchen Befehl unter dem x86 CPU Befehlssatz.

67 Stimmen

@AbidRahmanK obwohl die Intel-Asm-Syntax es wie eine Multiplikation aussehen lässt, kann der Lea-Befehl nur Schiebeoperationen kodieren. Der Opcode hat 2 Bits, um die Verschiebung zu beschreiben, daher kann man nur mit 1, 2, 4 oder 8 multiplizieren.

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