![]() |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Korrekt, da FMask ein Zeiger ist der im "Record" eines Objectes steht, musst du selber dereferenzieren. Ein Machinenbefehl zum direkten derefernezieren mehrerer Referenzen existiert dafür nicht. Es liegt also nicht an Delphi oder Assembler, sondern einfach an den Möglichkeiten der CPU.
Desweiteren nutze nicht deine obige Art des "Typcast" in ASM. Besser ist:
Delphi-Quellcode:
Ab D7 ist deine obige Syntax ungültig.
asm
MOV EBX,[EAX].TMyClass.FMask CMP EAX,[EBX].TMaskClass.FRect.Left end; Gruß Hagen |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Zitat:
beide Varianten werden sowohl in D5 (Anforderung) als auch in D7 (Deine Aussage) zu idetischem Code übersetzt. Obwohl ich den Cast in der Form AType(AVar) aus Konsistentzgründen mit der übrigen Delphi Language als angenehmer finde und die Variante AVar.AType zu Doppeldeutigkeiten führen kann, sofern man sich nicht an Nameskonventionen hält, wird die von Dir dargestellte Variante in ASM-Abschnitten von Borland verwendet (zB Unit System). Ich denke, dass man aus diesem Grund tatsächlich die zweite Notation verwenden sollte. |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Nein, ab D7 funktionieren nur die zweite Notation als Typcast, bzw genauer gesagt als korrekter Qualifier eines Recordelementes. Denn die erste Notation ist ein Pascaltypischer Typcast, die zweite Notation aber ein in Asm reguklärer Strukturqualifier.
Delphi-Quellcode:
Beides wären regulär gültige Syntax, aber nur der erste Fall wird ab D7 durch den inline Asm akzeptiert. Betrachtet man meine obige Aussage was der Unterschied beider Syntax sind (Typcast <> Qualifier) dann ist dies auch logisch. Auch ich habe dies erneut lernen müssen :) und meine nun das es korrekt war in D7 diese Syntax zu straffen.
type
TMyObject = class FProc: procedure(const Data; DataSize: Integer) of object; end; procedure TMyObject.Calc(const Data; DataSize: Integer); assembler; asm JMP DWord Ptr [EAX].FProc.TMethod.Code // in D7 JMP TMethod([EAX].FProc).Code // bis D7 möglich end; Gruß Hagen |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Interessant, Hagen.
Delphi-Quellcode:
funktioniert unter D7 tatsächlich nicht,
JMP TMethod([EAX].FProc).Code
Delphi-Quellcode:
hingegen schon :gruebel:
JMP TMethod([EAX]).Code
Ich konnte leider nichts zu "struktur qualifier", "struktur qualifizierer", "structure qualifier", etc. in unserem Kontext finden. Könntest Du auf eine Quelle verweisen oder das Prinzip, dass Du entdeckt hast, näher darstellen? Vielen Dank! |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
"Ich" habe da nichts entdeckt.
Es ist üblich in Assembler einen qualifizierten Bezeichner zu benutzen. Statt also einen Zeiger zu typcasten = umzubiegen und dem Compiler weiszumachen das der untypisierte Zeiger vom korrekten Typ ist, wird bei einem qualifizierten Bezeichner durch die Qualifizierung an sich Typsicherheit erzeugt. Statt also
Code:
wobei aber der Unterschied in Assembler besteht das EAX als Register das Auto enthält aber von sich aus ohne Typ ist. D.h. Auto im obigen Beispiel wäre in PASCAL ein Typ mit Typisierung TAuto und in Assembler ein stinknormaler Zeiger. Deshalb ist ein qualifizierter Bezeichner in Asembler auch ein impliziter "Typcast". Da aber in Assembler noch nie Typsicherheit bestanden hat, und man sich diese aber wünschte, hat man angefangen in die asm-Syntax "Record Typen" mit obiger Syntax ein wenig besser Typsicher zu machen.TTier(Auto).Laufe wird Auto.TTier.Laufe Der Unterschied besteht also in der Denkweise. Ein Typcast soll einen bestehenden Typ so erscheinen lassen als wäre es ein anderer Typ. Damit hebelt ein Typcast die Sicherheiten der Typüberprüfung des Compilers aus. Ein qualifizierter Bezeichner soll dagegen aus einer Typlosigkeit eine Typsicherheit erschaffen. Auf die Frage in diesem Thread projeziert heisst das das ein PASCAL like Typcast nichts in Assembler zu suchen hat, und das in Assembler die qualifizierten Bezeichner benutzt werden sollten. Das eine zerstört Typsicherheit und das andere erschafft sie. Gruß Hagen |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Hallo Hagen!
Vielen Dank für Deine Ausführungen. Es ist immer wieder ein Genuss, Deine Beträge zu studieren. Du hast folgendes Beispiel angeführt, wobei ich ehrlich gesagt noch nicht ganz verstehe, was der Code bezwecken soll.
Delphi-Quellcode:
Wieso verwendest Du den Operanten JMP und nicht CALL? Es geht doch darum, eine variable Methode zur Berechnung zu implementieren; ein für meine Begriffe sehr elegantes Programmierkonstrukt. Aber wie es geht nach dem Sprung zur Adresse Code und der Abarbeitung der Fkt weiter? Oder wird hier einfach der Stackframe der Methode Calc genutzt? Bitte um Aufklärung!
type
TMyObject = class FProc: procedure(const Data; DataSize: Integer) of object; end; procedure TMyObject.Calc(const Data; DataSize: Integer); assembler; asm JMP DWord Ptr [EAX].FProc.TMethod.Code // in D7 JMP TMethod([EAX].FProc).Code // bis D7 möglich end; Viele Grüsse OLLI |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Danke für Deine Ausführung Hagen, klar und schlüssig.
@OLLI: Da FProc identisch zur Methode Calc deklariert ist, ist in der dortigen Implementierung alles notwendige zum "Aufräumen" des Stacks und zum "Rückspringen" vorhanden (sofern FProc<>nil). Wolltest Du einen Call ausführen und wäre die Deklaration etwas komplexer, so dass nicht ausschließlich Register für die Überhabe verwendet werden oder wäre stattdessen ein stdcall oä verwendet worden, hättest Du diese Werte zunächst kopieren und erneut auf den Stapel legen müssen. In Hagens Implementierung hingegen, wird alles unangetastet gelassen und der Rücksprüng, der in FProc ausgeführt werden wird, nutzt die Adresse, die vom Klienten eigentlich für Calc gedacht war (ebenso verhält es sich mit den Parametern). Schön an der Lösung ist, dass man über den impliziten Paramter EAX und das Displacement (Offset des Attributs im Objekt) die Adresse der tatsächlich auszuführenen Methode "gratis mitbekommt". |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
HY Choose!
Viel gelernt von Euch beiden! :-D Also hab ich richtig vermutet. Dann ist auch sicher folgende Sicherheitsabfrage und Default-Berechnung möglich!? Wenn ihr schon mal da seid, quetsch ich euch auch aus.
Delphi-Quellcode:
OLLI
CMP [EAX].FProc, 0
JNE DWord Ptr [EAX].FProc.TMethod.Code // in D7 XOR EAX, EAX @Loop: ADD EAX, [EDX] INC EDX DEC ECX JNZ @Loop |
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Hallo OLLI,
ich gehe davon aus, dass Deine Implementierung nur Beispielhaft ist (es handelt sich um eine Prozedur, das Ändern von EAX bleibt daher ohne Effekt). Eine Default-Implementierung ist mit Sicherheit eine gute Sache, ich persönlich würde sie aber wiederum als Delphi-Methode implementieren und diese stattdessen absolut anspringen. Sofern Du nicht das letzte an Performance herausholen möchtest oder die Implementierung trivial ist (zB Result:= 0) würde ich immer zugunsten der Wartbarkeit und Übersicht entscheiden (zB mit Struktur-Qualifizierern ;)). Zwar macht Delphi keine Annahmen über irgendwelche Flags, allerdings möchte ich zu bedenken geben, dass der Vergleich
Code:
eben das Flagregister verändert. Solltest Du hinter FProc eine ASM-Implementierung legen, die auch aus anderen Situationen verwendet wird und dort weitere Informationen aus den Flags verwendet, solltest Du das noch berücksichten (weit hergeholt, ich weiß).
CMP [EAX].FProc, 0
|
Re: Delphi Inline Assembler Zugriff auf Privates Objekt
Zitat:
D.h. in EAX = Self, EDX = Data, ECX = Datasize, somit besteht der "Stackframe" in .Calc() nur aus der Rücksprungadresse. Ein CALL nach FProc würde also zusätzlich ein PUSH + CALL + RET mehr kosten als ein JMP. Die Methode in FProc kehrt also durch dem JMP sofort zum Aufrufer von .Calc() zurück. Man hätte also CALL nehmen können, aber warum ein PUSH + RET verschenken wenn man ein JMP nehmen kann ohne großen Aufwand im Quelltext zu machen. Es ging mir also nicht unbedingt darum den letzten Taktzyklus aus der CPU rauszuquetschen sondern nur darum das der Tipaufwand im Quelltext jeweils gleich ist, aber 2 Taktzyklen und ein paar Branches/Misses eleminiert werden. Wenn durch den JMP noch zusätzliche Parameteränderungen nötig gewesen wären dann hätte ich den CALL bevorzugt. Nungut, es sollte auch nur ein Beweis sein das ab D7 der inline Assembler strenger ist als in der Hilfe beschrieben wird. Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:15 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz