lea und Dekrement/Inkrement
-
In dem Code wird zuerst 8 nach edi geschoben und nach der zweiten Zeile enthält edi den Wert 7. Warum funktioniert in dem folgenden Code lea wie ein dekrement?
Zuerst scheibe ich den Fixwert nach edi. Danach lade ich doch aber die Adresse von edi+(-1) nach edi. Wieso funktioniert das und warum wird nicht einfach dec verwendet?
movl $8, %edi leal -1(%edi), %edi
Danke!
-
lea wertet einen speicheroperanden aus, anstatt allerdings auf den speicher zuzugreifen, wird die benutzte adresse dem ziel zugewiesen. das kann vorteilhaft sein, weil der speicherbezug jeden beliebigen modus verwenden kann - auf diese weise lassen sich bestimmte kompliziertere berechnungen durch einen befehl ausdrücken: im 32bit-modus besteht so ein adressbezug aus:
reg1 + reg2 * scale + offset
dabei sind reg1 und reg2 zwei beliebige register (oder auch ein und dasselbe), scale eine konstante (1,2,4 oderund offset eine beliebige konstante. sofern also ein arithmetischer ausdruck in dieser form darstellbar ist, hat man die möglichkeit, das ergebnis unmittelbar in einem befehl zu berechnen. es gibt dabei zwei dinge zu beachten:
- lea beeinflusst keine flags
- zumindest auf intel prozessoren ist es im regelfall deutlich langsamer als ein entsprechendes add,sub etc. sofern der ausdruck so einfach ist, dass er durch diese befehle zu berechnen wäre.
interessante anwendungen sind z.b. die schnelle multiplikation mit 3,5 und 9 (für 2,4,8 würde man shl benutzen):lea (%eax,%eax,2),%eax lea (%eax,%eax,4),%eax lea (%eax,%eax,8),%eax
warum in deinem fall kein dec verwendet wurde ist ohne den knotext nicht zu beantworten. zumal das ergebnis ja ohnehin feststeht, und man gleich 7 in edi speichern könnte.
-
Hallo und danke!
Ich bin darauf gestossen, als ich mir den asm Code angeschaut hab, den der GCC bei verschiedenen Optimierungen erzeugt. Folgende C Funktion erzeugt den asm Code:
int dec(int x) { return --x; }
/*Kompiliert für AMD64 mit -O3*/ dec: .LFB26: leal -1(%rdi), %eax ret
/*Ohne -O3*/ dec: .LFB5: pushq %rbp .LCFI0: movq %rsp, %rbp .LCFI1: movl %edi, -4(%rbp) leaq -4(%rbp), %rax decl (%rax) movl -4(%rbp), %eax leave ret
-
ja, gcc macht sich eine eigenschaft zu nutze, die - architekturbedingt - nur sehr wenige andere befehle ebenfalls haben:
das ziel der operation ist nicht gleichzeitig auch ein operand der operation - die verwendung von lea spart also einen mov-befehl ein.