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


Anmelden zum Antworten