Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   for Schleife in ASM (https://www.delphipraxis.net/73133-schleife-asm.html)

Luckie 12. Jul 2006 23:45


for Schleife in ASM
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nehmen wir mal folgenden Code:
Delphi-Quellcode:
var
  ar               : array[0..5] of integer = (0, 1, 2, 3, 4, 5);

  i, r             : integer;
begin
  r := 0;
  for i := 0 to 5 do
  begin
    inc(r, ar[i]);
  end;
  Writeln(r);
Egal was er macht, es ist jedenfalls eine Schleife, die wegen der Optimierung rückwärts läuft.

Der produzierte ASM Code sieht aus, wie im Anhang (CPU Fenster).

da steht jetzt:
Code:
dec edx
jnz -$08
jnz bedeutet, "Spring, wenn das Zero Flag nicht null ist." Aber das Zero Flag ist die ganze Zeit null. Kann man auch im Screenshot sehen. Erst wenn edx mit der Zählvariablen 0 erreicht hat, wird das Zero Flag auf 1 gesetzt und er springt nicht mehr. Der Code verhält sich also genau gegenteilig wie er eigentlich sollte. Oder habe ich da jetzt ein Verständnisproblem?

Muetze1 12. Jul 2006 23:51

Re: for Schleife ein ASM
 
JNZ = jump if not ZF

Die bedeutet, springe, wenn das Zero Flag (ZF) im Flags register nicht gesetzt ist. Wenn also ZF = 0, dann ist es nicht gesetzt. Es geht hier nicht um die 0 oder 1 welches ZF annehmen kann, sondern das Z steht für das Zero Flag. Und dieses ist nunmal 1, wenn eine vorherige mathematische Operation eine 0 ergeben hat. Mit anderen Worten: So lange EDX nicht 0 erreicht hat (was das ZF setzen würde), springe relativ 8 Bytes zurück (springe wenn ZF nicht gesetzt, jump if not ZF)

Luckie 12. Jul 2006 23:54

Re: for Schleife ein ASM
 
Hm. Dann habe ich das doch nur falsch verstanden. In meinem ASM Buch ist das aber auch etwas blöd erklärt. Puh ich dachte schon meine CPU wäre kaputt. :mrgreen:

Luckie 13. Jul 2006 00:01

Re: for Schleife ein ASM
 
Nachtrag:
Zitat:

An dieser Stelle wird die Zählvariable dekrementiert mit dec. dec hat die Eigenschaft, dass wenn das dekrementierte Register null wird das Zero Flag (ZF) zusetzen. Dies wird ausgenutzt, um mittels des Sprungbefehls jnz ("springe, wenn das Zero Flag (ZF) im Flags register nicht gesetzt ist") zu entscheiden, ob gesprungen werden muss oder nicht. Ist das Zero Flag nicht gesetzt (null), wird gesprungem und zwar in diesem Fall an eine Adresse 8 Byte zurück: $-08, was Adresse 00402561 wäre, und wie man sieht, ist das unser Schleifenrumpf. Ansonsten wird nicht gesprungen und im Code weitergemacht.

Und das, die Überprüfung eines Flags im Flagregister, ist einfachher und schneller als das Vergleichen zweier Register auf Gleichheit / Ungleichheit. Und das müsste man machen, wenn die Schleife vorwärts läuft, denn dann muss man ja die Zählvariable immer mit dem Endwert vergleichen, was bedeuten würde, dass man er mit dem ASM-Befehl cmp zwei Register vergleicht und erst dann ein Flag im Flagregister auswerten kann.
Stimmt der Text so?

Muetze1 13. Jul 2006 00:13

Re: for Schleife ein ASM
 
Ok, ansonsten nochwas:

jz = jump zero
jnz = jump not zero

Springe, wenn 0
Springe, wenn nicht 0

So kann man es sich vllt. auch leichter merken. Grundlegend hat es dein Assemblerbuch dann aber wirklich schlecht übersetzt (?) bzw. erklärt.

/EDIT: Ja, der Text stimmt so. Du hast nur einmal "register" klein geschrieben (wie zitiert). Ansonsten stimmt es so. Es klingt etwas verwirrend und man muss es zweimal lesen. Wenn das ein Tutorial werden soll, dann müsste man den ersten Teil vllt. nochmal anders formulieren um ihn zu entschärfen, weil beim ersten lesen verwirrt einen diese umgekehrte Logik recht stark.

Ansonsten noch ein Tipp: Als Argument kann man auch gleich nochmal die Opcodegrösse für CMP mit JE/JNE im Vergleich zu JNZ anführen. Ansonsten wäre auch noch allgemein anzumerken, dass sehr viele Operationen die Flags beeinflussen und viele Operationen vor allem das ZF mit setzen bzw. löschen. Dazu gibt es in den Unterlagen von Intel und AMD gute Tabellen. So z.B. bei AMD im Dokument #24594 AMD64 Architecture Programmer's Manual, Volume 3, General-Purpose and System Instructions auf Seite 178 (Dokument Seite 146) die Dokumentation der bedingten Sprünge und im Anhang E (Appendix E) findest du eine Tabelle wo aufgelistet wird, welches Flag im EFLAGS Register von welcher Instruktion beeinflusst wird (Seite 517, Dokument Seite 485).

Luckie 13. Jul 2006 00:17

Re: for Schleife in ASM
 
Ich habe es etwas umformuliert:
Zitat:

An dieser Stelle wird die Zählvariable dekrementiert mit dec. dec hat die Eigenschaft, dass wenn das dekrementierte Register null wird das Zero Flag (ZF) zusetzen. Dies wird ausgenutzt, um mittels des Sprungbefehls jnz ("springe, wenn das Zero Flag (ZF) im Flagsregister nicht gesetzt ist") zu entscheiden, ob gesprungen werden muss oder nicht. Ist das Zero Flag nicht gesetzt (null), wird gesprungen und zwar in diesem Fall an eine Adresse 8 Byte zurück: $-08, was Adresse 00402561 wäre, und wie man sieht, ist das unser Schleifenrumpf. Ansonsten wird nicht gesprungen und im Code weitergemacht.

Und das, die Überprüfung eines Flags im Flagregister, ist einfacher und damit schneller als das Vergleichen zweier Register auf Gleichheit / Ungleichheit. Und das müsste man machen, wenn die Schleife vorwärts läuft. In diesem Fall muss man die Zählvariable immer mit dem Endwert vergleichen, was bedeuten würde, dass man er mit dem ASM-Befehl cmp zwei Register vergleicht und erst dann ein Flag im Flagregister auswerten kann.

Muetze1 13. Jul 2006 00:19

Re: for Schleife in ASM
 
Jo, so lässt es sich einfach und verständlich in einem Zuge lesen. Ist nicht mehr so verwirrend wie zuvor. :thumb:

Luckie 13. Jul 2006 00:20

Re: for Schleife in ASM
 
OK, dann kommt es jetzt auf meine HP. ;)

http://www.michael-puff.de/Developer...ackwards.shtml

Muetze1 13. Jul 2006 00:26

Re: for Schleife in ASM
 
Doch noch was, da ich nicht genauen Artikel kenne, als Hinweis:

Zitat:

Zitat von Luckie
... wird gesprungen und zwar in diesem Fall an eine Adresse 8 Byte zurück: $-08, was Adresse 00402561 wäre, und wie man sieht, ist das unser Schleifenrumpf.

Die Instruktion steht an Adresse 0x00402567 und du springst 0x08 Bytes zurück und kommst auf 0x00402561 anstatt laut "Adam Riese" auf 0x0040255F. Daher die Frage ob du vorher schon darauf eingegangen bist, dass der Instruktion Pointer genutzt wird beim Sprung um die 8 Bytes ab zu ziehen und da er die Instruktion gerade abarbeitet, steht dieser schon auf der nächsten, also 0x00402569 und somit zieht er von dieser 8 Bytes ab.

Ich denke dass kann bei einer einzeln hier so gefallenen Äusserung ohne Erklärung zu Verwirrungen führen, da viele einfach die Instruktion suchen und von dem Offset subtrahieren, welcher links an dieser steht...

/EDIT: Was im Artikel nicht geklärt wird, bzw. worauf nicht hingewiesen wird...

Luckie 13. Jul 2006 00:31

Re: for Schleife in ASM
 
Wie bitte? Das habe ich jetzt, galube ich, nicht ganz verstanden. Es wird nicht acht Byte vom Offset zurückgesprumgen, sondern acht Byte vom Instruktionszeiger? Ist das gemeint?

Ich habe es jetzt so
Zitat:

in diesem Fall 8 Byte zurück: -$08, was Adresse $00402561 beim Instruktionszeiger entspricht, da der Instruktionszeiger schon bei $00402569 steht, und wie man sieht, ist das unser Schleifenrumpf
umformuliert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:58 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz