Zugriff auf Pointer-Inhalt



  • Hallo an alle,

    ich scheitere daran auf den Inhalt eines dynamischen Arrays zuzugreifen. Wenn ich unten stehende Template-Funktion (die nur Beispielcharakter hat und nur deshalb existiert, weil Sie mein Problem gut beschreibt) mit der Parameterliste ( 1, 2, 3, etc. ) Aufrufe, dann ändert mir mein Code die Adresse des arrays "t_array" auf 00000001, 00000002, etc.

    Ich greife also auf die Adresse und nicht auf den Inhalt zu. Kann mir jemand helfen?

    template<size_t t, class T>
    T* SetArray(...)
    {
    	int szArray = t;
    	static int* t_array = new int[szArray]();
    
    	_asm
    	{
    		mov ecx, szArray	// size_t in ecx
    		mov edx, 0			// schleifen variable
    		mov eax, 4			// first Parameter position - 4
    
    schleife:
    		cmp ecx, edx		// vergleiche size_t mit aktl. Position
    		je	_end			// gleich zum Ende, wenn equ
    		add eax, 4			// Inc. Parameter Position
    		mov ebx, [ebp+eax]
    		mov DWORD PTR t_array[edx], ebx
    		inc edx
    		jmp schleife		// zurück zur Schleife		
    
    _end:
    	}
    


  • Hallo FrEEzE2046,

    könntest Du bitte die Funktion in C++ schreiben, so wie Du sie Dir vorstellst, was sie machen soll, und hier posten. Irgendwie kann ich nicht verstehen, was Du genau machen willst...



  • abc.w schrieb:

    Hallo FrEEzE2046,

    könntest Du bitte die Funktion in C++ schreiben, so wie Du sie Dir vorstellst, was sie machen soll, und hier posten. Irgendwie kann ich nicht verstehen, was Du genau machen willst...

    Hallo,

    danke für die Antwort. Die Funktion soll folgendes machen:

    template< size_t t, class T >
    T* c_SetArray(T x1, T x2, T x3)
    {
    	static T* Array = new T[t];
    
    	Array[0] = x1;
    	Array[1] = x2;
    	Array[2] = x3;
    
    	return Array;
    }
    
    int main()
    {	double* dbl_array;
    	dbl_array = c_SetArray<3, double>(1.1, 2.2, 3.3);
    
    	for( int i = 0; i < 3; i++ )
    		cout << dbl_array[i] << endl;
    
    	return 0;
    }
    

    Das Ganze nur in Assembler und eben dynamisch mit undefinierter Parameterliste. Ich muss eigentlich nur wissen, wie ich auf den Inhalt von dem Array Zugreife. Ich ändere immer die Adresse, was natürlich nicht gewünscht ist.



  • Ach so, Du möchtest alle Parameter, die an die Funktion übergeben werden, in ein dynamisch angelegtes Array kopieren.
    Diese drei Befehle machen es ja schon im Prinzip:

    mov ebx, [ebp+eax]
            mov DWORD PTR t_array[edx], ebx
            inc edx
    

    So wie Du auf den Array zugreifst scheint für mich ok zu sein, Du benutzt die Adresse t_array[edx] und speicherst dort Inhalt von EBX. Das ist ok. Damit greifst Du tatsächlich auf den Inhalt vom Array. Allerdings wird EDX mit inc edx nur um 1 inkrementiert. Und das ist nicht ok. Du musst nämlich EDX um sizeof(T) Bytes inkrementieren... Dann hast Du ein weiteres Problem, dass z.B. sizeof(double) ist 8, also muss EDX jeweils um 8 inkrementiert werden, was man irgendwie implementieren kann, aber lesen vom Stack tust Du nur 4 Bytes, eben nur so viel, wie EBX aufnehmen kann. Und so wird es mit den Grössen nie richtig stimmen, je nach dem, wie das Template parametrisiert ist... Musst Du vielleicht anders überdenken.



  • Guten Morgen,

    eine Frage hätte ich dann doch noch. Wenn ich

    inc edx
    

    wird edx um 1 inkrementiert, dass ist mir schon klar. Wenn du aber sagst, dass ich edx um sizeof(T)-Byte inkrementieren muss, dann heißt das für mich auch, dass bei t_array[edx] "edx" nicht als Index verwendet wird.

    Zudem habe ich vor allem das Problem, dass ich im Debugger genau sehe, dass ich leider nicht den Inhalt des Arrays, sondern dessen Speicheradresse direkt verändere.

    Wie ich oben schon geschrieben habe: Nach dem Aufruf der obenstehenden Funktion liegt das Array an Position 00000001 etc. ...

    noch eine Idee?



  • Vielleicht inc DWORD PTR [edx]?



  • Melan schrieb:

    Vielleicht inc DWORD PTR [edx]?

    Nein, leider bringt das auch nichts.

    Das Problem beginnt schon bei der Ausfürung von diesem Code:

    mov edx, 0
    mov ebx, [ebp+8] 
    mov DWORD PTR t_array[edx], ebx
    

    Wenn hier edx 0 ist, so sollte das erste Elemente von t_array angesprochen werden. In ebx habe ich den ersten Parameter gespeichert.
    War dieser Parameter die Zahl 5, so soll die letzte Anweisung die 5 an die erste Stelle des Arrays schreiben.

    Was aber passiert ist, ist dass die Adresse von t_array verworfen und durch 00000005 ersetzt wird ...



  • FrEEzE2046 schrieb:

    Was aber passiert ist, ist dass die Adresse von t_array verworfen und durch 00000005 ersetzt wird ...

    Ok, Du hast mich angesteckt 🙂

    Ich habe mal den Code ausprobiert und es stimmt, was Du sagst. Dann habe ich ein wenig rumexperimentiert und folgendes ist dabei rausgekommen:

    #include <stdio.h>
    
    template<size_t t, class T> T* c_SetArray(...)
    {
        T* pStart = new T[t]();
        T* pEnd = &pStart[t];
    
        // Structure for debugging purpose to see what is on the stack
        struct _StackFrame
        {
            unsigned int EBP;
            unsigned int Address;
            double Param1;
            double Param2;
            double Param3;
        }
        * pStackFrame = NULL;
    
        _asm
        {
            mov pStackFrame, ebp     // for debugging only
    
            mov eax, 2          // Counter for DWORDs on the stack frame, start with 2nd DWORD
            mov edx, pStart
    
            Start:
            cmp edx, pEnd       // End of array reached?
            jge End
            mov ebx, [ebp + 4 * eax]    // read low 4 bytes of a parameter of type "double"
            mov [edx], ebx              // write to array
            inc eax
            mov ebx, [ebp + 4 * eax]    // get high 4 bytes of a parameter of type "double"
            mov [edx + 4], ebx          // write to array
            inc eax
            add edx, 8      // Increment pointer, sizeof(double) == 8
            jmp Start
    
            End:
        }
    
        return pStart;
    }
    
    int main(int argc, char *argv[])
    {
        double* dbl_array = NULL;
    
        dbl_array = c_SetArray<3, double>(1.0, 1.1, 1.5);
    
        for (int i = 0; i < 3; i++)
        {
            printf("%f\n", dbl_array[i]);
        }
    
        return 0;
    }
    

    Es funktioniert nur mit "doubles" oder anderen Datentypen, die genau 8 Byte groß sind... Wenn man die Funktion für andere Datentypen parametrisieren möchte, dann ist noch einiges zu tun. Ich würde es an deiner Stelle lassen und die Idee aufgeben. Es ist einfach viel zu aufwendig und vor allem, der Compiler würde an dieser Stelle viel besseren Code generieren. Das ist ja einer der Vorteile der Template-Funktionen, dass der Compiler anhand der gewählten Datentypen den bestmöglichen Code generieren kann...



  • abc.w schrieb:

    [Es funktioniert nur mit "doubles" oder anderen Datentypen, die genau 8 Byte groß sind... Wenn man die Funktion für andere Datentypen parametrisieren möchte, dann ist noch einiges zu tun. Ich würde es an deiner Stelle lassen und die Idee aufgeben. Es ist einfach viel zu aufwendig und vor allem, der Compiler würde an dieser Stelle viel besseren Code generieren. Das ist ja einer der Vorteile der Template-Funktionen, dass der Compiler anhand der gewählten Datentypen den bestmöglichen Code generieren kann...

    Erstmal vielen Dank für deine Mühen.
    Gut, es ließe sich für Typen wie Integer Char usw. schon realisieren, aber selbstverständlich hast du Recht, dass eine solche Funktion extrem tricky ist, da man viele Fälle bedenken muss.

    Ich glaube es ist aber etwas untergegangen, dass ich oben stehende Funktion nur exemplarisch für mein Problem auf arrays zu zugreifen genommen hatte. Von daher habe ich kein Problem die Idee aufzugeben 😉

    Und die Frage beantwortet hast du mir jetzt ja. Du zählst einfach die Adresse hoch und schreibst rein. Bei meinem Weg über den Index (t_array[index]) hat er mir immer die Adresse geändert.

    Hast du beim experimentieren auch den Grun dafür gefunden bzw. kannst du ihn mir sagen?



  • FrEEzE2046 schrieb:

    Hast du beim experimentieren auch den Grun dafür gefunden bzw. kannst du ihn mir sagen?

    Ja, der Grund ist folgender: Intel-Syntax 😉
    Diese Assembler-Zeile

    mov DWORD PTR t_array[edx], ebx
    

    bedeutet, "übertragen" auf C/C++ Syntax ungefähr folgendes:

    *(int*)(&(((char*)&t_array)[edx])) = ebx;
    

    D.h. die Adresse der Variable t_array wird genommen und nicht die Adresse, die in dieser Variable steht (diese Variable ist ja "zufällig" ein Pointer)...


Anmelden zum Antworten