Fehler im Code!
-
Hy,
Hab mal wieder ein Problem: Ich schreibe zurzeit an einem Compiler(nicht in ASM), der Basic-Quellcode scannt, parst und FASM-Code generiert. Soweit nurmal zu meinem eigentlichen Ziel. Ich möchte nämlich noch OOP einbauen und hab mir für diesen Zweck ein paar Funktionen geschrieben, nur funktioniert die Funktion FB_TYPE_Before nicht. Warum? Wo liegt der Fehler?format PE GUI 4.0 entry start include '\INCLUDE\win32a.inc' section '.data' data readable writeable ;Beim definieren eines Types(oder Klasse) wird diese Globale Variable erstellt TYPE_TEST dd 12,0,0,0 ;Das erste DWORD enthält die Größe, die das Object beim erstellen, bekommen soll. ;Das 2. DWORD beinhaltet den Pointer zum ersten Objekt, das 3. einen Pointer auf ;das vorletzte Object und des 4. einen auf das Letzte. ;Das Object wird in den ersten 4 Bytes einen Pointer aus das vorherige und in den ;zweiten 4 Bytes einen Pointer aus das nachfolgende Object enthalten. Die ;restlichen Bytes werden Attribute und Zeiger auf Methoden beinhalten. Diese Klasse ;enthält also folgerlich ein Attribut Gleich db "Gleich",0 Ungleich db "Ungleich",0 section '.code' code readable executable ;Der Einstiegspunkt: start: ;Hauptfunktion wird aufgerufen call WinMain ;Danach wird das Programm beendet push 0 call [ExitProcess] ;Die Hauptfunktion proc WinMain ;Zwei Lokale Variablen, die später die Pointer auf das erste und zweite Object enthalten local FirstObj:DWORD,SecondObj:DWORD ;Ein neues Object der Klasse Test wird erstellt und das Handle/der Pointer ;darauf in der Variable FirstObj gespeichert. push TYPE_TEST call FB_TYPE_New mov [FirstObj],eax ;Ein Zweites Object wird erstellt push TYPE_TEST call FB_TYPE_New mov [SecondObj],eax ;Ein Drittes push TYPE_TEST call FB_TYPE_New ;Und ein Viertes push TYPE_TEST call FB_TYPE_New ;Das Handle auf das erste Object wird abgefragt push TYPE_TEST call FB_TYPE_First ;das nach dem ersten folgende Object wird abgefragt(das Zweite) push eax call FB_TYPE_After ;Sichere eax, da es von Notify verändert wird push eax ;Prüfe ob das aktuelle ermittelte Object mit dem Zweiten übereinstimmt cmp eax,[SecondObj] je IstGleich2 push Ungleich call Notify jmp Ende_Abfrage2 IstGleich2: push Gleich call Notify Ende_Abfrage2: ;Wiederherstellung von eax pop eax ;Und das vorherige wird abgefragt(das Erste) push eax call FB_TYPE_Before ;+-------------------------------------------------------------+ ;| Hier ligt der Hund begraben! Als Rückgabewert kommt niemals | ;| der Pointer auf das erste Object heraus. | ;+-------------------------------------------------------------+ ;Prüfe ob das aktuelle ermittelte Object mit dem Ersten übereinstimmt cmp eax,[FirstObj] je IstGleich1 push Ungleich call Notify jmp Ende_Abfrage1 IstGleich1: push Gleich call Notify Ende_Abfrage1: ret endp ;Kleine Hilfsfunktion die einen Text in einer MessageBox ausgibt proc Notify Text:DWORD push 64 push 0 push [Text] push 0 call [MessageBox] ret endp ;Diese Funktion erstellt ein neues Object der angegebenen Klasse proc FB_TYPE_New Class:DWORD local CurrentObj:DWORD ;Ermittle die benötigte Größe des Objectes, also die ersten 4 Byte mov eax,[Class] mov dword eax,[eax] ;Allokiere den benötigten Speicher push eax push HEAP_ZERO_MEMORY call [GetProcessHeap] push eax call [HeapAlloc] mov [CurrentObj],eax ;Ermittle erstes Object der Klasse mov eax,[Class] mov dword ebx,[eax+4] ;Vergleiche mit 0, denn wenn es gleich Null ist handelt es sich um das erste Object cmp dword ebx,0 jnz IsNotFirst ;Wenn erstes Object mov eax,[Class] mov ebx,[CurrentObj] mov dword [eax+4],ebx ;Setzt aktuelles Obj. als Erstes ... mov dword [eax+8],ebx ;Vorletztes... mov dword [eax+12],ebx ;Und Letztes Obj. in der Klassenvariable jmp EndFirst IsNotFirst: mov eax,[Class] mov ebx,[CurrentObj] mov ecx,[eax+12] mov dword [ebx],ecx ;Speichert den Pointer auf das vorherige Object im aktuellen mov [eax+8],ecx ;Speichert den vorherigen als Vorletzten in der Klasse mov dword [ecx],ecx mov dword [ecx+4],ebx ;Speichert aktuelles Object als Nachfolgendes im vorletzten Obj. mov dword [eax+12],ebx ;Speichert aktuelles Obj. als Letztes in der Klasse EndFirst: ;Gibt das Handle des aktuellen Objects zurück mov eax,[CurrentObj] ret endp ;Diese Funktion liefert einen Zeiger auf das erste Object der Klasse proc FB_TYPE_First typ:DWORD mov eax,[typ] mov dword eax,[eax+4] ret endp ;Diese Funktion liefert einen Zeiger auf das letzte Object der Klasse proc FB_TYPE_Last typ:DWORD mov eax,[typ] mov dword eax,[eax+12] ret endp ;Diese Funktion ermittelt den Pointer auf das vorhergehende Object proc FB_TYPE_Before type:DWORD mov eax,[type] mov [eax],eax mov dword eax,[eax] ret endp ;Diese Funktion ermittelt den Pointer auf das nachfolgende Object proc FB_TYPE_After type:DWORD mov eax,[type] mov [eax],eax mov dword eax,[eax+4] ret endp section '.idata' import data readable writeable library kernel,'kernel32.dll',\ user,'user32.dll' import kernel,\ ExitProcess,'ExitProcess',\ HeapAlloc,'HeapAlloc',\ GetProcessHeap,'GetProcessHeap' import user,\ MessageBox,'MessageBoxA'
P.S. Hab's ein bisschen überkommentiert, zur besseren Lesbarkeit
mfg flona
-
Ohne das alles jetzt durchgegangen zu sein, sieht mir schon allein die FB_TYPE_Before nicht besonders sinnvoll aus.
Deshalb nur so als hint: Kannst du mal erklaeren, was diese Funktion eigentlich genau machen soll?
proc FB_TYPE_Before type:DWORD mov eax,[type] mov [eax],eax ;??? mov dword eax,[eax] ;??? Sinn? ret endp
-
In jedem Objekt wird ein Pointer auf das vorherige und auf das nachfolgende Object gespeichert. Die Funktion "FB_TYPE_Before" soll als Rückgabewert den Pointer des vorherigen Objectes ausgehend vom übergebenen Parameter, dem aktuellen Object, ermitteln. Dadurch kann ich mit einer speziellen Schleife alle Objecte einer Klasse aufrufen.
-
Aehm, ja, das hast du ja schon so in etwa in den comments geschrieben und das tut der Code tatsaechlich ja scheinbar so nicht.
Ich wollte eigentlich eher ein nochmaliges tieferes Sinnieren ueber den Code von FB_TYPE_Before (Zeile fuer Zeile) anregen.
-
sry hab die frage wohl iwie falsch verstanden und wenn ich so nachdenke, kann ich dir selber nichtmehr genau sagen was der Code soll *schäm*. In type steht ja der Pointer zu einem Objekt und am Ende sollten in eax die ersten 4 Bytes sein auf die der Pointer zeigt. Ich hab mal die Zahlen die bei before rauskommen mit dem Pointer FirstObj verglichen. Die Zahl die von before zurückegeben wird ist bei mir immer genau um 48 größer.
PS: könntest du mir vll falls vorhanden deine ICQ Nummer geben?
-
Oehm, ok. Dann solltest du dir vielleicht erst nochmal klar machen, was du da eigentlich programmiert hast.
So macht diese Prozedur IMHO wie mehrfach angedeutet zumindest nicht viel Sinn.ICQ oder andere Kontaktwege werde ich nicht herausgeben. Wozu auch? Wenn du auf Probleme stoesst, die du nicht loesen kannst, poste sie hier. Dafuer ist das Forum schliesslich da.
Nur in Ausnahmefaellen bin ich nach Anfrage in einem IRC-Chat zur Klaerung bestimmter(!) Probleme zu erreichen.
-
so gibt es mehr sinn, aber es funtz immer noch nicht:
proc FB_TYPE_Before type:DWORD mov eax,[type] ;Pointer auf das Object in eax mov dword eax,[eax] ;den Inhalt(dword) von eax(=dem Object) in eax ret endp
-
flona schrieb:
Die Funktion "FB_TYPE_Before" soll als Rückgabewert den Pointer des vorherigen Objectes ausgehend vom übergebenen Parameter, dem aktuellen Object, ermitteln.
Laut "FB_TYPE_New" soll der Pointer des "vorherigen Objekts" im dritten DWORD des "aktuellen Objekts" liegen:
proc FB_TYPE_Before type:DWORD mov eax,[type] mov eax,[eax+8] ret endp
-
Nein, da muss ich dir widersprechen.
mov eax,[Class] mov ebx,[CurrentObj] mov ecx,[eax+12] mov dword [ebx],ecx mov [eax+8],ecx ;Du meinst wohl diese Zeile? mov dword [ecx],ecx mov dword [ecx+4],ebx mov dword [eax+12],ebx
In eax ist nämlich der Pointer auf die KLasse und nicht auf das aktuelle Objekt:
KlassenVariable TYPE_TEST
1. DWORD: Größe des Objektes
2. DWORD: Pointer auf erstes Obj.
3. DWORD: Pointer auf vorletztes Obj. <- Dahin wird geschrieben
4. DWORD: Pointer auf letztes Obj.Objekt:
1. DWORD: Pointer auf vorheriges Obj.
2. DWORD: Pointer auf nachfolgendes Obj.
3. DWORD: Erstes Attribut
...
-
Tja, ich kann beim Druebersehen so jetzt auch nicht erkennen, woran es genau hakt und habe ehrlichgesagt auch nicht grossartig Lust, deinen Code fuer dich zu debuggen. Deine Funktion sieht jetzt zumindest erstmal halbwegs sinnvoll aus.
Also schau dir alles nochmal ganz genau an und bau halt einige Debug-Ausgaben (in der Konsole o.Ae.) ein oder benutze einen Debugger.
-
Hallo flona,
eine andere Alternative zu Deinem Assemblercode, wo Du verzweifelt versucht, irgendwelche Datenstrukturen zu implementieren, wäre eine "höhere" Sprache zu nehmen wie C oder C++... Es gibt in C z.B. ein nützliches Konstrukt, genannt "struct". Man könnte es folgendermassen einsetzen:
struct TYPE_TEST { uint32 nObjectSize; struct TYPE_TEST *pFirst; struct TYPE_TEST *pOneBeforeLast; struct TYPE_TEST *pLast; }
Ich finde es besser, weil 1) der Compiler macht sich Gedanken, wo die Elemente im Speicher stehen und wie man auf sie am Besten und am Schnellsten zugreift, 2) die Struktur ist innerhalb von Sekunden erweiterbar, ohne viel vom bestehenden Code kaputtzumachen, 3) man muss den Code nicht wochen- (monate?) lang debuggen.
Gruß,
abc.w
-
Hab den Fehler gefunden, nachdem ich das ganze nochmal neu geschrieben habe
Danke für alle Antworten