Autor |
Beitrag |
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 29.12.06 05:34
Hallo!
Jetzt hab ich auch mal ein Problem. Und zwar habe ich um ein mathematisches Problem zu lösen ein paar Zeilen Assembler geschrieben.
Daraus rufe ich eine Methode auf, die eigentlich meine Zahl in einen String in Binärdarstellung umwandeln und diesen in ein Memo schreiben soll.
Das Problem ist, dass beim Zugriff auf das Memo eine Schutzverletzung erscheint. Ich habe aber eigentlich das EBX Register wiederhergestellt usw.
Hier der Source, relativ umfangreich kommentiert:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102:
| procedure TfrmMain.btnStartClick(Sender: TObject);
function GetMask(FromIndex, Count: Integer): Integer; asm push eax mov cl, dl mov edx, $FFFFFFFF xor eax, eax shld eax, edx, cl pop ecx shl eax, cl end;
function RotateLeft(Value, RotateBy, Size: Integer): Integer; asm push ebx mov ebx, 1 shl ebx, cl mov ecx, edx @loop: shl eax, 1 test eax, ebx jz @nocarry add eax, 1 xor eax, ebx @nocarry: loop @loop pop ebx end;
procedure Print(uValue, uDummy, Size: Integer); var Output: string; begin Output := StringOfChar('0', Size) ; while uValue > 0 do begin if (uValue and 1) = 1 then Output[Size] := '1'; Dec(Size) ; uValue := uValue shr 1; end; memOutput.Lines.Add(Output); Values := Values + #13#10 + AnsiReverseString(Output); end;
procedure DoCalculation(a, b, Size: Integer); var Mask: Integer; asm push edx mov edx, eax mov eax, 0 push ecx push edx call GetMask pop edx pop ecx
mov Mask, eax mov eax, 0 pop edx @loopstart: xor eax, Mask push ecx push eax call Print pop eax pop ecx
push ecx call RotateLeft pop ecx
push eax push ecx call Print pop ecx pop eax
cmp eax, 0 jnz @loopstart end;
begin Values := ''; DoCalculation(StrToInt(edtA.Text), StrToInt(edtB.Text), StrToInt(edtUmfang.Text)); memOutput.Text := Trim(Values); ShowMessage(IntToStr(memOutput.Lines.Count)); end; |
Es wäre schön, wenn mir jemand sagen könnte, warum der Zugriff auf das Memo nicht klappt. Was habe ich falsch gemacht?
Das Projekt hänge ich zum Testen auch komplett an.
// EDIT: Ich habe gerade festgestellt, dass das Projekt auf dem PC meiner Eltern nicht korrekt läuft... Keine Fehlermeldung, es passiert einfach nicht das richtige...
Danke,
Schönen Gruß,
Sebastian
Einloggen, um Attachments anzusehen!
|
|
Logikmensch
      
Beiträge: 390
Win XP
Delphi 2007 Prof., XE2, XE5
|
Verfasst: Fr 29.12.06 11:06
Ich habe mir den Code genauer angeschaut, kann aber auch beim besten Willen keinen Fehler sehen. Auch alle von Delphi vorgeschriebenen Register (hier nur EBX) stellst Du sauber wieder her, und PUSHs zu POPs sind auch okay. Ich würde daher empfehlen, mal mit Hilfe des Debuggers zu schauen, ob beim Erreichen des CALL PRINT und Reinspringen in die Print-Routine der Debugger in der Lage ist, die Lokale Variablen OUTPUT, UVALUE usw. korrekt auszuwerten, wenn er das tut, liegt's an was anderem. Auch beim Debuggen muss innerhalb von PRINT die Auswertung von MEMOUTPUT.LINES.COUNT möglich sein.
Ansonsten musst Du die Routinen nochmal einzeln testen. An dem Aufruf von Assembler nach Delphi muss es nicht unbedingt liegen. Sieht meiner Meinung nach ok aus.
_________________ Es gibt keine Probleme - nur Lösungen!
|
|
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 08.01.07 21:54
Deine GetMask-Routine könnte IMHO noch etwas optimiert werden ...
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
| function GetMask(FromIndex, Count: Integer): DWORD; asm MOV ECX, EAX MOV EAX, 1 XCHG EDX, ECX SHL EAX, CL DEC EAX XCHG EDX, ECX SHL EAX, CL end; |
Sollte im Allgemeinen schneller sein, da kein Stack genutzt wird ... Außerdem werden keine erweiterten Befehle genutzt ... d.h. es läuft auch auf alten Delphi-Versionen ...
Kannst Du mal schauen, welche genaue Fehlermeldung er Dir in besagter Zeile liefert?
Ach ja: Hab deinen Fehler ... Grad noch mal ganz scharf hingeschaut
Ist ein allgemeines Feature lokaler Prozeduren in einem OOP-Kontext: SDer Self-Zeiger steht nicht zur Verfügung (Stack-Frame); Delphi nimmt aber fälschlicherweise an, dass dies der Fall ist. Kannst Du dadurch lösen, dass Du entweder Self explizit an Print übergibst ODER auf die Formular-Variable.DeinMemo.Lines.Add zugreifst ... Ich würde dir letzteres in deinem Fall empfehlen, da Du ASM und Native mischt und daher der Zugriff auf Self etwas kompliziert ist ...
_________________ 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.
|
|
Allesquarks
      
Beiträge: 510
Win XP Prof
Delphi 7 E
|
Verfasst: Di 09.01.07 02:13
Was soll eigentlich dein rotateleft machen frage ich mich die ganze Zeit. Das funktioniert aber so wie gewollt???
|
|
jaenicke 
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 09.01.07 03:20
 Auf die Idee, die Einsen so zu erzeugen hätte ich auch selber kommen können...
So geht das GetMask natürlich besser...
Und was den Fehler angeht: Du hast Recht, ich hab daraus frmMain.memOutput.Lines.Add gemacht und dann ging es.
Ich bin aus dem Assembler-Code nicht so ganz schlau geworden, deshalb hab ich nicht gesehen, was Delphi eigentlich macht. Also ich meine, wie es versucht auf das Memo zuzugreifen. Und leider ist mir nicht ganz klar, wie Delphi das intern mit Self macht. Naja, mal googeln...
Jedenfalls vielen, vielen Dank, jetzt geht es wie es soll...
Allesquarks hat folgendes geschrieben: | Was soll eigentlich dein rotateleft machen frage ich mich die ganze Zeit. Das funktioniert aber so wie gewollt??? |
Um das auch nicht unbeantwortet zu lassen:
Ich möchte nur z.B. 12 Bits betrachten. Nun rotiere ich um 2 Bits nach links. Dann muss jeweils nach dem Rotieren um Eins danach das 15. Bit auf das erste gepackt werden. Die Rotate-Befehle von Assembler können aber nur ganze DWord / Word / etc. Werte rotieren...
Beispiel:
Ich betrachte nur die niederwertigsten 12 Bit, hier also die rechten:
0000 10 10 00000000
Die vier Nullen Links sollen also ignoriert werden, jetzt rotiere ich um 2:
0000 1000 000000 10
|
|
Allesquarks
      
Beiträge: 510
Win XP Prof
Delphi 7 E
|
Verfasst: Di 09.01.07 04:43
Achso hab den dritten Parameter einfach nicht verstanden. Aber dafür brauchst du doch gar keine Schleife, aber wens funzt dann kann ich auch verstehen wenn de das nicht mehr ändern willst:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| function rotateleft(value,size,steps:integer):integer; asm push esi; push ebx;
rol eax,cl; mov ebx,eax;
xchg ecx,edx; ror ebx,cl; mov esi,$FFFFFFFF; shl esi,cl; not esi; and eax,esi; xchg ecx,edx; mov esi,$FFFFFFFF; shl esi,cl; and eax,esi; not esi; and ebx,esi; or eax,ebx; pop ebx; pop esi; end; |
|
|
jaenicke 
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 09.01.07 05:44
Ja, dass das so ungefähr gehen müsste, ist mir gerade in dem Moment durch den Kopf geschossen, als ich geschrieben habe, was die Funktion macht  . Ich habs aber dann doch nicht versucht. (Hatte gerade mit einem anderen Thread hier zu tun, wo ich ne Grafik zur Erklärung eines Speicherlecks gemacht habe...)
Deine Funktion funktioniert jedenfalls zwar einzeln, aber leider nicht eingebaut im Programm. Naja, ich werd aber den Fehler bestimmt noch finden. Aber den suche ich später...
Danke jedenfalls!
Allesquarks hat folgendes geschrieben: | aber wens funzt dann kann ich auch verstehen wenn de das nicht mehr ändern willst: |
Es geht hier weniger darum, dass es geht... Dann hätte ich es auch in Delphi schreiben können.
Nein, ich will mich mal wieder intensiver mit Assembler beschäftigen, denn das ganze was ich vor 5 Jahren im Rahmen meines kleinen "Betriebssystems" mal gelernt hatte hab ich schon wieder vergessen. (Es gibt ungefragt eine Liste aller Dateien im Hauptverzeichnis aus und sagt dann Hatschi. Wenn man dann Gesundheit eingibt, dagt es Danke  , und das wars --> Resetknopf  .)
Aber für die Semesterferien im März plane ich eine Neuauflage, diesmal vielleicht mit so sinnvollen Befehlen wie Beep  . Auch will ich mal nicht nur das Hauptverzeichnis der Diskette auslesen, wie das letzte Mal, sondern vielleicht auch Unterordner. Naja, mal sehen...
|
|
|