CreateThread of non-staticle or virtual Memberfunctions,...


  • Mod

    Und wer braucht das? Man kann es auch machen ohne auf Hacks zurückzugreifen.
    Wie es geht habe ich beschrieben...

    Dir ist klar, dass der this Zeiger nicht bedeutet, dass die vtable, die Du für die Funktion benötigst an dieser Stelle liegt?
    Die ist klar, dass ein Funktion-Member Zeiger eine Struktur ist, die aus einem this Zeiger plus einem Offset besteht?

    Nochmal: Um es für den Compiler richtig zu machen und nicht alles durch casts plattbügeln zu lassen würde ich lieber zu einer kontrollierten Übergabe neigen.



  • Martin Richter schrieb:

    Und wer braucht das? Man kann es auch machen ohne auf Hacks zurückzugreifen.

    Ja, im allgemeinen wird das evtl. nicht benötigt. Da sich ja aber die Addy, trotz fester Basisaddresse, der vtbl zu jeder Laufzeit ändert, würde dies einen "hackschutz" bedeuten.

    Der hauptgrund jetzt ist aber wohl eher um noch etwas zu lernen, daher bitte ich um ein bisschen geduld mit mir. 🙂

    Wie es geht habe ich beschrieben...

    jup,..siehe oben,... danke

    Dir ist klar, dass der this Zeiger nicht bedeutet, dass die vtable, die Du für die Funktion benötigst an dieser Stelle liegt?

    Ich verstehe jetzt nicht ganz was Du meinst.
    Die addy des vftbl eintrages für die aufzurufende memberfkt bekomme ich durch

    Run my_ptr=&_thread::_thread_handler::run;
    

    Der this ptr ist hingegen nur ein ptr zum datensegment der Instanz.
    (bitte um korrektur wenn ich mich hier irre...)

    Die ist klar, dass ein Funktion-Member Zeiger eine Struktur ist, die aus einem this Zeiger plus einem Offset besteht?

    Da bitte ich nochmal um klärung, da ich nicht ganz verstehe was Du hier meinst. 😕
    Denn prinzipiell ist ein fktptr sowie ein MFP (member function pointer) nichts weiter als ein offset (der unteranderem nach dem aufruf auf dem callstack abgelegt wird...) .

    Der this ptr (bei MFP's) sowie die parameter werden je nach callconvention in register (this ptr bei __stdcall in ecx)in dementsprechender reihenfolge abgelegt.
    Daher verstehe ich nicht das du meinst mit this+0hXX = offset der member function ?????

    Grüße und dank 😃



  • Was ist eine addy? 🙄



  • Entschuldige:
    Addy = addresse , hier ist damit ein offset gemeint. Im speziellen der Offset der Vtable.

    Greetz 🙂


  • Mod

    Schau Dir mal einen MFKT Ptr im Speicher an. Er hat bei der MS Implementierung für 32bit eine Größe von 64bit...

    Eine gute Beschreibung dazu hat Raymond Cheang geschrieben, ob in seinem Blog oder seinem Buch weiß ich aktuell nicht mehr.



  • Hi Martin,

    jetzt weiß ich was Du mit der Struktur meinst.

    Wenn eine Klasse aus zwei Basisklassen besteht:
    (folgend als multibles derivat bezeichnet)
    ||===== ||
    || base 1 ||
    ||===== ||
    || base 2 ||
    ||===== ||
    | derived |
    |====== |

    dann muss um eine methode aus der basis2 klasse aufgerufen werden der this ptr
    adjustiert werden. D.h. der pointer zu der member funktion ist eine "reale"
    struktur, bestehend aus dem eigentlichen offset der member funktion (pointer)
    plus der größe einer size_t, dem Adjustor, welchen den this ptr auf das
    Datensegment der zwoten basisklasse "konvertiert"
    (im endeffekt ne offset addition).

    Bei einer Vererbung aus nur einer Basisklasse hingegen, ist der pointer auf
    einen member der Basisklasse, nur so groß wie ein pointer.
    (Auf 32bit systemen halt 4 byte)

    "The size of a pointer-to-member-function can change depending on the class!"

    Ferner sollte man keine MFP eines multiblen derivats in eine MFP der basis casten, da sich sonst die größe des pointers ändert.

    Quellen:
    http://www.agner.org/optimize/calling_conventions.pdf
    http://blogs.msdn.com/b/oldnewthing/archive/2004/02/09/70002.aspx
    (Von Chen hatte ich jetzt direkt nix gefunden,.. ausser der historie von callin' conventions..)
    -------------------------------------------------------------------------------

    Da der Adjustor vor dem Aufruf der Basismethode greift, wird dann der pure (offsetkorregierte) this ptr übergeben. Die Frage die sich jetzt an diesem Punkt stellt ist:

    Wie sieht der this ptr einer virtuellen basis methode bei einem multiblen derivat aus, wenn dies einen eintrag in der vtable erzeugt ????

    Das werde ich mir heute auf jedenfall noch anschauen 😃

    Grüüße und Dank,..
    ..anregungen sind willkommen



  • Hi,
    also ich habe mal auf die schnelle etwas gebastelt:

    class Base1
    {
    public:
    	virtual void bm1(void) {};
    };
    
    class Base2
    {
    public:
    	virtual void bm2(void){};
    };
    
    class derived:Base1,Base2
    {
    public:
    	void bm2(void){};
    };
    

    Und hier die dissambly, ich hoffe ich habe diese richtig übersetzt

    Base2 * dptr= new Base2; // addresse: 0x013a6ee8
    
    	dptr->bm2();
    // hole die addy des dptr ptrs 
    012510D2  mov         eax,dword ptr [ebp-34h]
    // sichere die addy der vtable nach edx
    012510D5  mov         edx,dword ptr [eax] 
    // sichere this pointer im ecx
    012510D7  mov         ecx,dword ptr [ebp-34h] 
    // hole die addy der methode aus der vtable und sichere es in eax
    012510DA  mov         eax,dword ptr [edx] 
    // aufruf der methode
    012510DC  call        eax  
    
         derived * dptr2 = new derived;
    
           dptr2->bm2();
    //hole die addy des pointers 
    0125111D  mov         ecx,dword ptr [ebp-38h] 
    //adjustiere +4 byte für den call (this konvertierung)
    01251120  add         ecx,4 
    //hole pointer der instanz
    01251123  mov         eax,dword ptr [ebp-38h]
    // Hole die addy der vtable
    01251126  mov         edx,dword ptr [eax+4] 
    //hole den offset der member func aus der vtable (von Base2)
    01251129  mov         eax,dword ptr [edx] 
    //und call
    0125112B  call        eax
    

    Für mich heißt das, egal ob ich die virtuellen _thread::_thread_handler::_start
    in einem multiblen derivat nicht überlade und dafür aber ::run , müsste ich also
    den this ptr den ich übergebe NICHT anpassen.

    Ich kann halt zwar auf die vererbten elemente der basis1 nicht zugreifen aber
    immer noch auf die der basis2 und die im derivat deklarierten, da sie im
    speicherbereich nach dem ende von dem der basis2 liegen.

    Da aber so eine polydeklaration ja so oder so nicht erlaubt ist:

    Base2 _ptr= new derived; //error C2243
    

    brauche ich mir um solch einen fall auch ja keinen kopf machen,...

    Falls ich aber umgekehrt die ::_start überlade, und die ::run nicht, muss ich also
    darauf achten das der this ptr adjustiert wird.

    Die oft genutzte polmorphe konvertierung üder die von Martin vorgeschlagene
    externe (statische) ThreadProc funktion (siehe erste seite) würde aber aufgrund von C2243
    Fehlschlagen, wenn es sich um ein multibles derivat handelt, ausser der this
    pointer wird vorher adjustiert oder nicht???

    D.h. Ich müsste so oder so den this pointer vor der übergabe
    adjustieren, egal ob es sich um eine externe ThreadProc oder eine interne
    vrituelle meberfunc handelt, auch wenn es allein des datensegment geht.

    dringendes RFC (Request for Comments 😃 )

    Grüße und dank...



  • Hier steht auch noch einiges über (Member-)Function-Pointer.



  • ..danke asd,

    darauf habe ich aber schon in der ersten seite des Threads referenziert 😃



  • Oh sorry! Ich hatte mir den Thread durchgelesen, den Link aber anscheinend übersehen. Naja, hab ich ihn halt bestätigt oder so 🙂


Anmelden zum Antworten