Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Diverse Fragen zum Assembler Operator call (https://www.delphipraxis.net/11980-diverse-fragen-zum-assembler-operator-call.html)

OLLI_T 18. Nov 2003 11:18


Diverse Fragen zum Assembler Operator call
 
Mahlzeit Leute!

Neues Thema, neues Glück. Hier sind so ein Paar sehr gute Leute unterwegs; das muss man nutzen.

Ich möchte ganz allgemein fragen, was ich bei einem Methoden- bzw. Funktionsaufruf aus einer Assembler-Klassenmethode heraus zu beachten habe. Das die ersten beiden Übergabeparameter - sofern vorhanden - ins EDX bzw. ECX Register geladen werden müssen ist klar!

1. Ich habe das Register EAX benutzt und somit ist der Zeiger auf das Objekt Self verloren gegangen. Muss ich vor einem Methodenaufruf das Register wiederherstellen oder passiert das automatisch?

2. Wie bewerkstellige ich die Übergabe von mehr als zwei Parameter. Genau diese Problematik steht mir nämlich nun bevor.

Ein konkretes Beispiel soll die Fragestellung verdeutlichen. Die Funktion Horzline soll via call aufgerufen werden:

Delphi-Quellcode:
Procedure TDIBSection24.HorzLine(X1,X2,Y:DWord);
Der Assembler Code dazu wird dann etwa so aussehen:

Delphi-Quellcode:
Var SicSelf:TDIBSection24; XStart,XEnd,YPos:DWord;
  asm
    mov SicSelf, eax // Ist das notwendig?
    push ecx
    push edx
    mov eax, SicSelf // Ist das notwendig?
    mov edx, XStart
    mov ecx, XEnd
    // Wie definiere ich Parameter "Y"?
    Call HorzLine
    pop ecx
    pop ecx
Vielen Dank schon mal und guten Hunger.

OLLI

choose 18. Nov 2003 11:23

Re: Diverse Fragen zum Assembler Operator call
 
Hallo OLLI,

irgendwann einmal hatte ich eine verdammt gute Ausarbeitung, die nicht nur mehrere Parameter, Methoden und Datentypen wie Double zu diesem Thema, sondern ebenfalls das ShortString-Handling als Funktionsergebnis behandelte. Leider verbummelt.

Habe das nur überflogen, aber vielleicht hilft es: http://thunder.prohosting.com/~whiskey7/issue02.htm

choose 18. Nov 2003 11:43

Re: Diverse Fragen zum Assembler Operator call
 
Hallo OLLI,

das hatte ich vergessen:
Zitat:

Zitat von OLLI_T
1. Ich habe das Register EAX benutzt und somit ist der Zeiger auf das Objekt Self verloren gegangen. Muss ich vor einem Methodenaufruf das Register wiederherstellen oder passiert das automatisch?

Der Code (das Verhalten), der hinter einer Methode liegt, ist statisch und wird von allen Exemplaren einer Klasse (und ggf deren Erben) geteilt. Die Exemplarvariablen (der Zustand) des Objekts wird durch diese Methoden ggf verändert. Hierzu muss die Methode "wissen", wo die Daten liegen.
Wenn Du nun die Methode Foo aus der Methode Bar heraus aufrufst,
Delphi-Quellcode:
c:= Self.Foo(a,b);
erwartet Foo die selben Parameter, als wenn Du die Methode als Klient aufrufst
Delphi-Quellcode:
c:= AnObject.Foo(a,b);
(inkl des impliziten Parameters, der Referenz auf das Objekt).
Der Code ist in beiden Fällen identisch, allerdings könnte ein anderes Objekt gemeint sein, diese Information "steckt in EAX" und kann auch nicht vom Compiler zur Übersetzung Aufrufs generiert werden (schließlich ist ihm unbekannt, für welches Objekt Bar aufreufen wurde).
Vielleicht hast Du im Debugger schon einmal die Aussage "Auf Self kann aus Optimierungsgründen nicht zugegriffen werden" gelesen? Der Compiler hat hier erkannt, das die Referenz nicht länger benötigt wird und brauchte sie vorher auch nicht auf dem Stack ablegen. Wenn Du die "Referenz auf Self" verlierst, kannst Du weitere Methoden nicht länger korrekt aufrufen.

Anmerkung:
Sofern die Methode (und alle aus ihr aufgerufenen) den Zustand des Exemplars nicht liest oder verändert, ist es problemlos, undefinierte Werte in EAX zu übergeben.

Ich hoffe das war nicht zu wirr... :gruebel:

OLLI_T 18. Nov 2003 13:32

Re: Diverse Fragen zum Assembler Operator call
 
HY Choose!

OK, also werde ich EAX brav in Ruhe lassen bzw. sichern, sofern ich noch ne weitere Klassenmethode aufrufen möchte! Das mit der Optimierung und Self wird damit auch verständlich.

Dann könnte ich eigentlich ausführlich schreiben:

Delphi-Quellcode:
  Call [EAX].HorzLine
Das entspricht dann in Pascal:

Delphi-Quellcode:
  Self.HorzLine(XStart,XEnd,Y);
Das mit der Parameterübergabe ist mir allerdings trotz des guten Links noch nicht ganz geläufig. Die Daten müssen auf den Stack und gemäß der Standardaufrufkonvention register von links nach rechts. Somit muss ich mein Beispiel von eben wohl in dieser Art erweitern:

Delphi-Quellcode:
Var SicSelf:TDIBSection24; XStart,XEnd,YPos:DWord;
  asm
    mov SicSelf, eax // Das muss sein!
    push ecx
    push edx
    mov eax, SicSelf // Das muss sein!
    mov edx, XStart
    mov ecx, XEnd
    push Y
    Call HorzLine
    pop Y
    pop edx
    pop ecx
Werde das mal testen, ob ich damit hinkomme! Dir noch einen schönen Nachmittag.

OLLI

negaH 18. Nov 2003 14:00

Re: Diverse Fragen zum Assembler Operator call
 
Self sollte in EAX stehen, muß aber nicht unbedingt. Wenn zB. die aufgerufene Methode statisch ist und keinerlei Zugriffe auf Self macht und keine weiteren Methoden aufruft, dann wird Self nicht benötigt. Dies ist aber extrem selten der Fall.
In EAX in einer Methode steht also entweder das Object selber, oder aber bei Klassenmethoden der Klassentyp der Klasse.

Nun, je nachdem was für eine Methode aufgerufen wird unterscheidet sich der Assembler:

Delphi-Quellcode:

type
  TMyObject = class
   
    procedure StaticMethod;
    procedure VirtualMethod; virtual;
    procedure DynamicMethod; dynamic;
    class procedure ClassDynamicMethod; dynamic;
  end;

asm
   CALL TMyObject.StaticMethod

   MOV  EDX,[EAX]
   CALL DWord Ptr [EDX + VMTOffset TMyObject.VirtualMethod]

   PUSH ESI
   MOV  ESI,DMTIndex TMyObject.DynamicMethod
   CALL System.@CallDynaInst

   MOV  ESI,DMTIndex TMyObject.ClassDynamicMethod
   CALL System.@CallDynaClass
   
   POP  ESI
end;
Es ist also sinnvoll in Assembler sich auf statische Methoden zu beschränken, da auch DMTIndex und VMTOffset nicht in jeder Delphi Version definiert sind.

Man sieht auch sehr schön das überschriebene Methoden "override" ein Problem darstellen können. Haben wir eine Objectdeklaration in der überschriebene Methoden vorkommen, so wissen wir nicht, ohne die Basisklassen zu kennen, ob es eine virtuelle oder dynamische Methode ist. Somit wissen wir dann auch nicht nach welcher Art & Weise wir im Assembler vorzugehen haben.

Gruß Hagen

PS: übrigens kann man das in der Hilfe zur Inline Assemblersyntax nachlesen :)

negaH 18. Nov 2003 14:05

Re: Diverse Fragen zum Assembler Operator call
 
Willst du sichergehen, und denoch schnell un effizient auf virtuelle/dynamische methoden zugreifen so gehts auch so:

Delphi-Quellcode:
var
  M: procedure of object;
begin
  M := Self.DynaMethod;
  asm
    MOV  EAX,M.Data
    CALL M.TMethod.Code
  end;
end;
Gruß hagen

choose 18. Nov 2003 14:10

Re: Diverse Fragen zum Assembler Operator call
 
Zitat:

Zitat von negaH
PS: übrigens kann man das in der Hilfe zur Inline Assemblersyntax nachlesen :)

Danke für den Tipp Hagen, dort steht ua:
Zitat:

Typbezeichner können zur einfachen und schnellen Erstellung von Variablen verwendet werden. Die folgenden Anweisungen erzeugen denselben Maschinencode, der den Inhalt von [EDX] in das Register EAX lädt:
Code:
MOV    EAX,(TRect PTR [EDX]).B.X
MOV    EAX,TRect([EDX]).B.X
MOV    EAX,TRect[EDX].B.X
MOV    EAX,[EDX].TRect.B.X

Wir wissen's inzwischen ja aber besser ;)

Hast Du vielleicht ein Dokument der Art, wie ich es verloren habe und OLLI weiterhelfen könnte ("Parameterübergabe und Ergebnisrückgabe in Delphi aus Sicht der Maschine")?

choose 18. Nov 2003 14:17

Re: Diverse Fragen zum Assembler Operator call
 
@OLLI: ...Und wenn Du einmal "fast" die Lösung sehen willst, wie die "Referenz auf Self" automatisch geladen wird, guck Dir mal
Delphi-Quellcode:
{ Standard window procedure }
{ In   ECX = Address of method pointer }
{ Out  EAX = Result }

function StdWndProc(Window: HWND; Message, WParam: Longint;
  LParam: Longint): Longint; stdcall; assembler;
asm
   //...
        MOV    EAX,[ECX].Longint[4]
        CALL   [ECX].Pointer
        ADD    ESP,12
        POP    EAX
end;
an und verfolge, wie denn nun tatsächlich der Wert nach ECX kommt...
Lustige Variante, die insbesondere deshalb Interessant weil seit D5 unverändert und die Adresse von WndProc des Fensterhandles "von außen" ermittelbar ist ;)

negaH 18. Nov 2003 14:22

Re: Diverse Fragen zum Assembler Operator call
 
Zitat:

Lustige Variante, die insbesondere deshalb Interessant weil seit D5 unverändert
Seit D1 ist sie schon so. Sie hat aber auch den Nachteil das die nötigen Daten in Speicherblöcken die mit GlobalAlloc() alloziert wurden abgelegt sind. Das so allseits bekannte 8k Speicherloch in DLL's mit VCL Controls rührt daher. Denn dieser Minimalblock kann bei der Terminierung einer solchen DLL nicht autom. freigegeben werden, ohne das dabei mit schweren Abstützen zu rechnen ist.

Gruß Hagen

choose 18. Nov 2003 14:34

Re: Diverse Fragen zum Assembler Operator call
 
Zitat:

Zitat von negaH
Seit D1 ist sie schon so.

Habe mit einer D1->D3 Migration mit Delphi begonnen, um meine Arbeiten dann mit einer D3->D5 Migration fortzusetzen...

Dort bin ich erst auf diese und ähnliche Verfahren aufmerksam geworden, die man auch nutzen kann, um Win32-API-CallBacks auf Methoden inkl des Zustands eines beliebigen Objekts zu "weiterzuleiten"...

Noch einmal meine Frage, Hagen :cyclops:: Hast Du zum Thema "Parameterübergabe und... mit ASM", "Nette Dinge, die man mit ASM und Delphi hinbekommt", "Pitfalls using Delphi and ASM" etc. Artikel oder sonstige Beiträge, die das Thema zusammenhängend darstellen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:59 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