![]() |
Inline Assembler in Methoden
Hi,
Ich hatte bisher eine Assemblerroutine als ganz normale Funktion in meiner Unit. Jetzt bin ich grad dabei das ganze bisschen hübsch zu verpacken und dabei hab ich unter anderem auch diese Routine in eine neue Klasse gesteckt. Allerdings kam da was ganz anderes raus als wenn ich direkt die alte Funktion aufrufe. Ich hab dann mal kurzerhand aus function foobar: TMyType; register; ein class function foobar: TMyType; register; static; gemacht, dann läuft auch die Funktion der Klasse richtig. Kann es sein, dass mir der self Pointer vorher den Stack zerschossen hat? die static Methode hat ja nun kein self mehr. Gibts trotzdem ne Möglichkeit inline-ASM in Methoden zu verwenden ohne die gleich static zu machen? Vielleicht reicht ja einfach ein pop esp; :gruebel: |
Re: Inline Assembler in Methoden
Na klar gibts die Möglichkeit!
Am Anfang einer Methode kann so einiges passieren. Unter anderem wird self als erster Parameter übergeben. Zeig doch mal, was du gemacht hast! Edit: Hier mal eine Methode von mir (stdcall)
Delphi-Quellcode:
function TParserReal.in_calc:double;
//Aufruf von implemtierter Funktion asm mov eax,[esp+8] //self nach eax push esi push edi mov edi,[eax].FKonstanten //Konstantenarray in edi mov esi,[eax].Fin_args //Variablenarray in esi lea edx,[eax].Fv0 //Pointer auf 0 nach edx xor ecx,ecx //ecx löschen (Fehlerzähler) call [eax].[Ffunc] //Aufruf von implemntierter Funktion pop esi pop edi mov eax,[esp+8] //self nach eax mov [eax].Ffehler,ecx //Fehlerzähler speichern end; |
Re: Inline Assembler in Methoden
Delphi-Quellcode:
Die Funktion selbst ist nur als function getSerial: TCPUID; deklariert. Da kracht es dann.
function
TmpllCpuSerial.getSerial; register; asm PUSH EBX PUSH EDI MOV EDI,EAX MOV EAX,1 DW $A20F STOSD MOV EAX,EBX STOSD MOV EAX,ECX STOSD MOV EAX,EDX STOSD POP EDI POP EBX end; Mach ich eine class function draus und diese static läuft alles wie es soll. So ist TCPUID deklariert: TCPUID = array[1..4] of Longint; brauch ich da stdcall für? oder geht das auch ohne? |
Re: Inline Assembler in Methoden
Hallo,
bei Methoden steht in Register EAX der Self-Zeiger. Die Adresse des Rückgabewertes findest du in Register EDX. Gruß Hawkeye |
Re: Inline Assembler in Methoden
Delphi-Quellcode:
Edit: Du musst nicht zwingend irgend eine Aufrufkonvention nehmen. Du musst dich nur an diese halten (was du ja auch gemacht hast, außer dass du self nicht beachtet hast).
function TForm1.getserial:TCPUID;
{in self --> EAX (Das self gibts nur bei Methoden, @TCPUID --> EDX (sonst landet der erste Parameter gleich in EAX) } asm PUSH EBX PUSH EDI MOV EDI,EDX //aus EAX wird EDX MOV EAX,1 CPUID STOSD MOV EAX,EBX STOSD MOV EAX,ECX STOSD MOV EAX,EDX STOSD POP EDI POP EBX end; |
Re: Inline Assembler in Methoden
D'ohhhh....
okay, muss ich irgendwas beachten bzgl. Register? Darf ich bestimmte Register nicht modifizieren? (also vorher dann mit push und pop wiederhierstellen) Muss z.B. in eax immer ein Zeiger auf self sein oder kann ich das Register problemlos modifiziert lassen? Grad noch was anderes festgestellt: also wenn ich jetzt eax gegen edx tausche bekomme ich wieder die richtigen Rückgabewerte angezeigt. Soweit so gut. Aber ich hab eine Funktion die true zurückgibt:
Delphi-Quellcode:
Da Funktioniert das mit AL. Ersetz ich AL durch DL bekomm ich ein False zurück... Also wiso ist das hier jetzt AL und NICHT DL?
function
TmpllCpuSerial.cpuidAvailiable; register; asm PUSHFD {direct access to flags no possible, only via stack} POP EAX {flags to EAX} MOV EDX,EAX {save current flags} XOR EAX,ID_BIT {not ID bit} PUSH EAX {onto stack} POPFD {from stack to flags, with not ID bit} PUSHFD {back to stack} POP EAX {get back to EAX} XOR EAX,EDX {check if ID bit affected} JZ @exit {no, CPUID not availavle} MOV AL,True {Result=True} @exit: end; |
Re: Inline Assembler in Methoden
*von hinten aushol*
Also: Bei der Aufrufkonvention "register" (= Delphi Standard) landen die ersten 3 Übergabeparameter in EAX, EDX, ECX, der Rest im Stack. Wenn du eine Methode hast, ist der erste Parameter immer "self", ansonsten eben nicht und in EAX steht der erste "reguläre" Übergabeparameter (wenn es ihn denn gibt), der dann bei einer Methode wie gesagt auf Position 2 (also nach EDX) geht. In einer Funktion/Methode kannst du mit EAX, EDX und ECX machen was du willst. Alle anderen Register müssen erhalten bleiben. Umgekehrt kannst du, wenn du eine Funktion aufrufst nicht erwarten, dass EAX, EDX und ECX am Ende der Funktion mit den gleichen Werten gefüllt sind 32-Bit Rückgabewerte (Boolean, integer, smallint, byte, ...) landen immer in EAX. Fließkommawerte werden in der FPU zurückgegeben. Bei records wird als letzter Parameter ein Pointer auf das record übergeben. Was heisst dass für dich? Den Normalfall hast du in "cpuidAvailiable". Unabhängig ob "normale" Funktion oder Methode. In EAX landet das Ergebnis. Bei getSerial passt das Record allerdings nicht vollständig in EAX. Deswegen schafft die aufrufende Funktion etwas Platz auf dem Stack (für den record) und übergibt einen Pointer darauf als zusätzlichen Parameter. In dem Fall ist es der einzige und er landet deswegen gleich hinter self in EDX. |
Re: Inline Assembler in Methoden
okay, danke für die ausführliche Erklärung :dp:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:14 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-2025 by Thomas Breitkreuz