Autor |
Beitrag |
Jakob_Ullmann
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Mi 25.11.09 19:33
Hallo!
Ich hab mir gedacht, ich könnte mich mal ein wenig mit Assembler beschäftigen. Deshalb hab ich angefangen, folgendes zu lesen: de.wikibooks.org/wik...ssor)-Programmierung
Ich bin jetzt in etwa hier: de.wikibooks.org/wik...te_Assemblerprogramm (sehr weit  )
Dort steht:
Zitat: | Mit dem mov Befehl wird der zweite Operand in den ersten Operanden kopiert. Der erste Operand wird auch als Zieloperand, der zweite als Quelloperand bezeichnet. Beide Operanden müssen die gleiche Größe haben. Wenn der erste Operand beispielsweise die Größe von zwei Byte besitzt, muss auch der zweite Operand die Größe von zwei Byte besitzen.
Es ist nicht erlaubt, als Operanden das IP-Register zu benutzen. Wir werden später mit Sprungbefehlen noch eine indirekte Möglichkeit kennen lernen, dieses Register zu manipulieren.
Außerdem ist es nicht erlaubt, eine Speicherstelle in eine andere Speicherstelle zu kopieren. Diese Regel gilt für alle Assemblerbefehle mit zwei Operanden: Es dürfen niemals beide Operanden eine Speicherstelle ansprechen. Beim mov -Befehl hat dies zur Folge, dass, wenn eine Speicherstelle in eine zweite Speicherstelle kopiert werden soll, dies über ein Register erfolgen muss. Beispielsweise wird mit den zwei folgenden Befehlen der Inhalt von der Speicherstelle 0110h in die Speicherstelle 0112h kopiert: |
Meiner Meinung nach ist das ein Widerspruch. Was ist nun damit gemeint, bzw. was ist mit "Speicherstelle" gemeint? Ein Register, ein Byte, ein Segment, eine Adresse?
Ich verstehe da irgendwie gerade nur Bahnhof. Insbesondere habe ich ja nicht vor, ein komplettes Programm in Assembler zu schreiben. Es geht mir hauptsächlich um den in Delphi eingebetteten Assembler. Wie soll ich denn dann mit Adressen umgehen? Die können doch jedes Mal anders sein! Moderiert von Narses: Topic aus Off Topic verschoben am Sa 19.12.2009 um 19:19
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Mi 25.11.09 19:39
bei dem in delphi-eingebettetem assembler benutzt du keine adressen, sondern einfach die Variablennamen aus delphi.
Du kannst halt nicht schreiben
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| var a, b: cardinal; begin asm mov a, b end; end; |
sondern musst schreiben
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| var a, b: cardinal; begin asm mov eax, b; mov a, eax; end; end; |
Es darf halt entweder vom Ram ins Register oder vom Register ins ram, aber nie von Ram zu Ram...
Edit: Ich war schneller...
Zuletzt bearbeitet von Boldar am Mi 25.11.09 19:50, insgesamt 1-mal bearbeitet
|
|
uall@ogc
      
Beiträge: 1826
Erhaltene Danke: 11
Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
|
Verfasst: Mi 25.11.09 19:42
Du kannst nicht von einer Adresse Daten direkt in eine andere Adresse kopieren sondern musst einen Umweg über den Stack bzw. ein Register machen
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| mov dword ptr [$12345678], dword ptr [$87654321] mov eax, dword ptr [$87654321] mov dword ptr [$12345678], eax push dword ptr [$87654321] pop dword ptr [$12345678] |
also nur ein ptr. (wenn man jetzt wieder genau ist, dann ist das push sowas ähnliches, wenn esp auf die zieladresse zeigt)
_________________ wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
|
|
Jakob_Ullmann 
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Mi 25.11.09 19:58
Vielen Dank euch beiden! Aber einwas wäre noch interessant: Geht denn dann Register nach Register, z. B. mov eax, edx?
uall@ogc: Deinen Code verstehe ich nicht, aber das ist hoffentlich auch noch nicht so schlimm. Was dword und ptr bedeuten, werde ich ja hoffentlich demnächst lernen.
|
|
Boldar
      
Beiträge: 1555
Erhaltene Danke: 70
Win7 Enterprise 64bit, Win XP SP2
Turbo Delphi
|
Verfasst: Mi 25.11.09 19:59
Jakob_Ullmann hat folgendes geschrieben : | Vielen Dank euch beiden! Aber einwas wäre noch interessant: Geht denn dann Register nach Register, z. B. mov eax, edx?
uall@ogc: Deinen Code verstehe ich nicht, aber das ist hoffentlich auch noch nicht so schlimm. Was dword und ptr bedeuten, werde ich ja hoffentlich demnächst lernen. |
Register nach Register geht auch.
dword ist in dem fall eine Größenangabe, also dass die variable ein dword ist.
Ptr und die [] bedeuten zusätzlich, dass es sich um einen Pointer auf einen DWORD handelt, also sind die Zahlen in den Klammern die Adressen.
|
|
Jakob_Ullmann 
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Mi 25.11.09 22:05
Danke, das war ebenfalls halbwegs verständlich. Den Rest kriege ich hoffentlich irgendwie gebacken...
|
|
Jakob_Ullmann 
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Sa 19.12.09 20:14
Ich glaube, es ist doch noch nicht alles klar. Und zwar stand ich letztens mit der Aufgabe konfrontiert, zwei Zeichen in einem String zu vertauschen. Mit Delphi in wenigen Sekunden erledigt. Aber irgendwie schien mir das zu langweilig und ich wollte mal ausprobieren, ob ich es auch in Assembler gebacken kriege. Ich habe also folgendes probiert:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function Swap(s: string; i: Integer): string; var a: char; begin asm mov eax, s[i] mov a, eax mov eax, s[i + 1] mov s[i], eax mov eax, a mov s[i + 1], eax end; Result := s; end; |
Ich hätte höchstens erwartet, dass der Code nicht das macht, was er soll, aber Delphi gibt ja gleich mal Compilerfehler aus (ungültige Registeroperation). Jede Speicherstelle in jeder Zeile wird rot unterkringelt.
Warum ist das so falsch und wie müsste es richtig heißen?
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Sa 19.12.09 20:58
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| procedure Swap(var s: string; i: Integer); asm test eax, eax jz @@e
xchg cl, byte ptr[eax+edx] xchg cl, byte ptr[eax+edx+1] xchg cl, byte ptr[eax+edx] @@e: end; |
Nicht mit Compiler getestet, dürfte aber  Problem ist bei Strings die Referenzzählung. Die müsste man für ASM nämlich selber machen ... Außerdem beachten, dass ich ohne Stackframe arbeite.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Jakob_Ullmann 
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Mo 21.12.09 17:05
Zitat: | Nicht mit Compiler getestet, dürfte aber  |
Ich habe auch gerade keinen Delphi-Compiler zur Hand, aber wenn du sagst, das geht, vertraue ich dir einfach mal.
Verstehe ich nicht. Muss man das so kompliziert machen oder geht das auch einfacher?
Warum sollte das funktionieren? Dort kommt doch nirgends auch nur einmal s oder i vor. Hat das was mit dem jz @@e zu tun?
Was mir gerade einfällt: Gibt es eigentlich eine Möglichkeit (bzw. ich gehe davon aus, dass es eine gibt  ), sich den von Delphi erzeugten Assemblercode anzusehen? Würde mich mal interessieren, wie Delphi den Code umsetzt (wäre sicher auch hilfreich).
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 21.12.09 17:32
Jakob_Ullmann hat folgendes geschrieben : | Zitat: | Nicht mit Compiler getestet, dürfte aber  |
Ich habe auch gerade keinen Delphi-Compiler zur Hand, aber wenn du sagst, das geht, vertraue ich dir einfach mal. |
Wenn ich schreibe "nicht getestet", dann heißt das genau das
Jakob_Ullmann hat folgendes geschrieben : | Verstehe ich nicht. Muss man das so kompliziert machen oder geht das auch einfacher? |
Das ist schon die einfachste Variante ... Man muss das mit dem XCHG nur mal eben per Hand durchexerzieren, dann sieht man, auch warum
Jakob_Ullmann hat folgendes geschrieben : | Warum sollte das funktionieren? Dort kommt doch nirgends auch nur einmal s oder i vor. |
Ich nutze die Register-Vorbelegung, die Delphi intern nutzt direkt. Zuordnung der Register ist immer EAX, EDX, ECX für die ersten drei Parameter, danach Stack. Wenn man auf die Parameternamen zugreift, dann baut Delphi da manchmal dermaßen merkwürdige Stackframes, da verzichte ich liebend gerne drauf.
Jakob_Ullmann hat folgendes geschrieben : | Hat das was mit dem jz @@e zu tun? |
Das JZ @@e prüft nur, ob überhaupt ein String übergeben wurde. Der Vollständigkeit halber müsste man eigentlich noch eine Prüfung des Indizes machen, aber die hab ich mir mal gespart für das Beispiel.
Jakob_Ullmann hat folgendes geschrieben : | Was mir gerade einfällt: Gibt es eigentlich eine Möglichkeit (bzw. ich gehe davon aus, dass es eine gibt ), sich den von Delphi erzeugten Assemblercode anzusehen? Würde mich mal interessieren, wie Delphi den Code umsetzt (wäre sicher auch hilfreich). |
Breakpoint setzen, CPU-Fenster öffnen.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Jakob_Ullmann 
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Mo 21.12.09 18:52
Cool, danke!
EDIT: OK, mir ist doch noch was aufgefallen. Du schreibst test eax, eax. Was macht das test nun wieder? Oder gehört das mit dem jz @@e irgendwie zusammen? Ist das Absicht oder ein Fehler, dass beide Argumente eax sind?
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 21.12.09 19:16
Jakob_Ullmann hat folgendes geschrieben : | Cool, danke!
EDIT: OK, mir ist doch noch was aufgefallen. Du schreibst test eax, eax. Was macht das test nun wieder? Oder gehört das mit dem jz @@e irgendwie zusammen? Ist das Absicht oder ein Fehler, dass beide Argumente eax sind? |
Ja, die beiden Zeilen gehören zusammen. Wird das etwa aus der visuellen Gliederung nicht klar  ???
TEST verknüpft die beiden argumente bitweise mit UND und schreibt das Ergebnis des Vergleichs in die CPU-Flags. Von dort frag ich das Ergebnis mit JZ ab ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Jakob_Ullmann 
      
Beiträge: 1747
Erhaltene Danke: 15
Win 7, *Ubuntu GNU/Linux*
*Anjuta* (C, C++, Python), Geany (Vala), Lazarus (Pascal), Eclipse (Java)
|
Verfasst: Mo 21.12.09 20:32
|
|
|