![]() |
Float-Parameter per ASM übergeben
Hi,
Ich habe gerade sowas:
Delphi-Quellcode:
Diese Methode würde ich gerne über ASM aufrufen, ich scheitere jedoch beim Versuch... Es kommt immer nur 0 an.
procedure TForm1.Test(f: Single);
begin ShowMessage(FloatToStrF(f,ffNumber,2,2)); end;
Delphi-Quellcode:
Was muss ich da anders machen?
mov edx, [Params]
mov edx, [edx] // nicht so wichtig.. Float wird in edx geladen mov eax, Self call TForm1.Test Gruß Neutral General |
Re: Float-Parameter per ASM übergeben
Warum schaust du nicht einfach in der CPU-Ansicht nach?
Es sieht so aus, als ob Floats in jedem Fall auf den Stack geschoben werden müssen. |
Re: Float-Parameter per ASM übergeben
Hi,
Ja das habe ich auch durch das CPU-Fenster herausgefunden, aber es funktioniert bei mir nicht... :
Delphi-Quellcode:
Es kommt trotzdem 0 an... :gruebel:
procedure TForm1.Button2Click(Sender: TObject);
begin asm push 3.4 call TForm1.Test end; end; |
Re: Float-Parameter per ASM übergeben
Konstante Floats solltest du als Konstanten deklarieren, andernfalls kann es in BASM zu seltsamen Effekten kommen.
|
Re: Float-Parameter per ASM übergeben
Hi,
Ok ich habs gemerkt... Naja das Problem ist, das ich den Float-Wert über ein Array of Const bekomme. Das ganze sieht also so aus:
Delphi-Quellcode:
Was kann ich tun?procedure TForm1.Button1Click(Sender: TObject); begin Test.FloatDings([2.1]); end; procedure TTest.FloatDings(Params: Array of Const); begin asm mov edx, [Params] mov edx, [edx] push edx mov eax, Form1 // egal jetzt^^ call TForm1.Test end; end; procedure TForm1.Test(f: Single); begin ShowMessage(FloatToStrF(f,ffNumber,2,2); end; Gruß Neutral General |
Re: Float-Parameter per ASM übergeben
Mitdenken!
Ein Array of const ist, wie dir sicherlich bekannt ist, ein Array of TVarRec mit spezieller Längenangabe. Jetzt schau dir doch bitte mal an, wie Floats in TVarRec gespeichert wird (System.pas). In jedem Fall als Extended und nie als Single oder Double, außerdem noch als Zeiger. Also musst du ein bisschen anpassen, denn du hast noch einen Zeiger mehr, den du dereferenzieren musst. Grundsätzlich hast du jetzt die Wahl, TForm1.Test so zu verändern, dass es Extendeds entgegennimmt, oder in FloatDings ein wenig mit der FPU herumzuspielen. |
Re: Float-Parameter per ASM übergeben
Hi,
Oh du hast ja Recht :oops: Hatte sogar mal gesehn das sie im TVarRec als PExtended gespeichert werden aber ich hatte es irgendwie wieder vergessen :wall: Naja dann wollte ich anfangen an den Wert hinter dem PExtended zu kommen. Der erste Schock war aber dann da, als ich sehen musste das SizeOf(Extended) = 10... Was ist denn das für ein "krummer" Wert?! Ich dachte bisher immer Extendeds wären auch 8 Byte groß.. :shock: Also habe ich mir das mal im CPU-Fenster angeschaut: Zitat:
Delphi-Quellcode:
*) Ich bin leider ziemlich unerfahren was ASM betrifft...
// edx: PExtended
mov eax,[edx] mov ecx,[edx+4] // ... mov [eax+4],ecx // mov [eax+4],[edx+4] compiliert nicht *) mov word ptr [eax+8],[edx+8] // *) + hab ich auch nicht anders hinbekommen Ich denke ich verstehe den Code aus dem CPU-Fenster, aber ich kanns nicht auf meine Situation übertragen :( Gruß Neutral General |
Re: Float-Parameter per ASM übergeben
Delphi-Quellcode:
Oder über SSE ;)
asm
fld tbeyt ptr [edx] fstp tbyte ptr [eax] end; Edit: Stimmt, qword waren nur 8. |
Re: Float-Parameter per ASM übergeben
Hier denkst du mal wieder zu kompliziert. :angel: Eigentlich willst du doch nur den Extended-Wert auf den Stack schieben, damit du die Funktion aufrufen kannst.
Delphi-Quellcode:
Damit sollte es klappen.
// edx: PExtended
push word ptr [edx + 8] //zuerst gepusht -> liegt am weitesten weg, daher fangen wir hinten an push [edx + 4] push [edx] Übrigens, wegen deines Erstaunens über SizeOf(Extended): Intel verwendet drei Größen für Floats: 4 Byte (Single), 8 Byte (Double = Real) und 10 Byte (Extended). Im Inline-Assembler sprichst du Extended für fld und fst(p) mit TByte an (vermutlich steht das für "ten byte"). |
Re: Float-Parameter per ASM übergeben
Hi Dax und Apollonius,
@Dax: Habs jetzt so gelöst wie Apollonius gesagt hat, aber ich werd mir diese Float-Befehle auch mal angucken.. Kann ja nichts schaden was dazuzulernen ;) @Apollonius: Danke, es funktioniert, aaber ( :mrgreen: ) es taucht ein ganz seltsamer effekt auf:
Delphi-Quellcode:
:arrow:
// Diese Funktion rufe ich auf f = 2.1
procedure TForm1.Test3(f: Extended); begin ShowMessage(FloatToStrF(f,ffNumber,5,2)); end; Zitat:
PS: Ich poste nochmal grad wie das ganze aufgerufen wird:
Delphi-Quellcode:
PS: Bitte nicht meine Methode optimieren... Es funktioniert so weit und dadrüber bin ich froh.. nachher hab ich zwar tollen Code, aber der ist dann nicht von mir sondern von sonst jemandem und das mag ich nicht :?
procedure TForm1.Button1Click(Sender: TObject);
begin Form1.ExecuteScriptMethod('Test3',[2.1]); end; procedure TForm1.ExecuteScriptMethod(Method: String; Params: array of Const); var proc: Pointer; i, off: Integer; max: Integer; p1,p2: Integer; begin proc := MethodAddress(Method); max := Length(Params); for i:= 2 to max-1 do begin off := i*8; // stack-parameter pushen (floats noch nicht eingebaut!) asm mov edx, [Params] add edx, off mov edx, [edx] push edx end; end; // 1 - 3. Parameter übergeben (wobei 1. Parameter = Self) p1 := Params[0].VType; p2 := Params[1].VType; asm mov eax, max and eax, eax jz @Self // Kein Parameter sub eax,1 jz @Param1 // 1 Parameter, sonst 2 Parameter @Param2: mov ecx, [Params]; add ecx, 8 mov ecx, [ecx] @Param1: mov edx, [Params] mov edx, [edx] mov eax, p1 // wenn Params[0].VType = vtExtended (3) sub eax, 3 jnz @Self // dann float pushen push word ptr [edx+$08] push [edx+$04] push [edx] @Self: mov eax,self // self übergeben call proc // methode aufrufen end; end; Gruß Neutral General |
Re: Float-Parameter per ASM übergeben
Was erhältst du denn, wenn du das mal so aufrufst?
Delphi-Quellcode:
Edit: Syntax korrigiert
procedure TForm1.Aufruf(Params: array of const);
begin Test3(TVarRec(Params[0]).vExtended^); end; |
Re: Float-Parameter per ASM übergeben
Hi,
Dann funktionierts... :? Ach ja... diese riesen ShowMessage lässt sich auch nicht wegklicken... :shock: |
Re: Float-Parameter per ASM übergeben
Setze mal einen Haltepunkt auf den Anfang von Test3 und gehe dort in die CPU-Ansicht und schaue dir den Stack an. Wo ist der Unterschied zwischen den Aufrufen?
|
Re: Float-Parameter per ASM übergeben
Hi,
hier zwei Screenshots. (Das ist doch der Stack oder?) Der Stack bei normalem Aufruf:
Delphi-Quellcode:
procedure TForm1.ExecuteScriptMethod(Method: String;
Params: array of Const); begin Test3(Params[0].VExtended^); exit; // weiterer Code end; ![]() und wenn ichs über meine Methode aufrufe: (siehe Post weiter oben) ![]() Kann da jedoch nichts reininterpretieren... Gruß Neutral General |
Re: Float-Parameter per ASM übergeben
Ah, hier liegt eindeutig ein Alignment-Problem vor (ich kann allerdings nicht sagen, warum dass zu diesem seltsamen ShowMessage führt). Ich dachte, dass bei push word xyz automatisch auf ein DWord erweitert wird, anscheinend wird aber tatsächlich nur ein Word gepusht und ESP entsprechend nur um 2 verringert.
Ändere das mal so ab:
Delphi-Quellcode:
//statt
push word ptr [edx+$08] //das verwenden: movzx eax, word ptr [edx+$08] push eax |
Re: Float-Parameter per ASM übergeben
Hi,
Also du hast mir bisher sehr geholfen. Es tut mir Leid, aber ich muss nochmal weiter nachfragen :? :wall: Ich habe jetzt die "Float-Kompatibilität" auf die Parameter 3-n erweitert (bzw 4-n wenn man Self mitzählt), also die Parameter die auf dem Stack abgelegt werden. Jedoch kommt bei mir in der Funktion immer nur der Wert: -3,6854775808e-3509. Außerdem erhalte ich die Exception: "Ungültige Gleitkommaoperation in meiner Test4-Procedure:
Delphi-Quellcode:
Hab mir auch den Stack angeguckt: Ich glaube da ist diesesmal nichts verschoben, er sieht jetzt immer total anders aus...
procedure TForm1.Test4(b: Byte; S: String; f: Extended); //b und S sind nur damit f der dritte parameter sein kann
begin ShowMessage(S + ' ' + FloatToStrF(f,ffNumber,5,2) + IntToStr(b)); end; Hier der Code:
Delphi-Quellcode:
Apollonius... *hundeblick* :mrgreen:
procedure TForm1.ExecuteScriptMethod(Method: String;
Params: array of Const); var max,off: Integer; proc: Pointer; begin proc := MethodAddress(Method); max := Length(Params); for i:= 2 to max-1 do begin off := i*8; asm mov edx,[Params] add edx,off movzx ecx,[edx+$04] // Params[i].VType --> ecx sub ecx,3 // if Params[i].VType = vtExtended jnz @NoExt movzx ecx, word ptr [edx+$08] // then... push ecx push [edx+$04] push [edx] jmp @LoopEnd @NoExt: // else push [edx] @LoopEnd: end; end; // edx,ecx Parameter und eax = Self Parameter folgen end; |
Re: Float-Parameter per ASM übergeben
Du hast vergessen, den PExtended zu dereferenzieren. An den Anfang der Float-Behandlung muss noch ein mov edx, [edx].
|
Re: Float-Parameter per ASM übergeben
Zitat:
wird nicht hier beim pushen in einem dereferenziert
Delphi-Quellcode:
:?:
movzx ecx, word ptr [edx+$08]
push ecx push [edx+$04] push [edx] Wobei es trotzdem nicht funktioniert. (gleiches Problem wie vorher)
Delphi-Quellcode:
EDIT:
for i:= 2 to max-1 do
begin off := i*8; asm mov edx,[Params] add edx,off mov edx,[edx] // <--- hinzugefügt movzx ecx,[edx+$04] sub ecx,3 jnz @NoExt movzx ecx, word ptr [edx+$08] push ecx push [edx+$04] push [edx] jmp @LoopEnd @NoExt: push [edx] @LoopEnd: end; end; Wenn ich
Delphi-Quellcode:
durch
movzx ecx,[edx+$04]
Delphi-Quellcode:
ersetze, dann geht es o.O Warum das denn?
mov ecx,[Params]
add ecx,off add ecx,4 movzx ecx,[ecx] |
Re: Float-Parameter per ASM übergeben
Nach
Delphi-Quellcode:
Steht in edx ein Zeiger auf einen TVarRec. Folglich steht dann mit movzx ecx,[edx+$04] in ecx vType, wenn du kein mov edx,[edx] davor einfügst.
mov edx,[Params]
add edx,off Mit dem movzx ecx, word ptr [edx+$08] hast du dann allerdings in ecx schon den Anfang des nächsten TVarRec - schließlich zeigt edx auf einen, und SizeOf(TVarRec) ist 8. Wenn du allerdings davor noch ein mov edx, [edx] einfügst, zeigt edx nicht mehr auf den TVarRec, sondern auf den Extended, und dann stimmt alles. Du solltest das mov edx, [edx] also am besten direkt nach jnz @NoExt einfügen. Warum deine andere Lösung funktioniert, ist dann auch klar: Du hast zwar das mov edx, [edx] zu früh ausgeführt, aber um dir den vType zu holen, startest du von neuem und ignorierst den falschen Wert von edx. Allerdings wird es dann unangenehm für nicht-Floats. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:42 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