Code on the fly



  • Hi!

    Gibts eine Möglichkeit, Code dynamisch einzubinden, außer als DLL? Wenn ich quasi Assembler-Code zur Laufzeit erzeuge oder aus einer Datei lade (nur den Code für eine Funktion), kann ich den irgendwie aufrufen?



  • Moin,
    das würd mich auch sehr interessieren.
    In Java kann man ja z.b. Klassen dynamisch nachladen.
    Aber wie siehts mit den Restlichen Sprachen aus?

    MFG



  • Badestrand schrieb:

    ...kann ich den irgendwie aufrufen?

    Du kannst Dir einen Funktionspointer definieren, der mit der Startadresse des generierten Codes initialisiert wird.
    Mit 'casten bis zum Absturz' kann die Startadresse auch die Adresse einer Variablen (Array) sein.
    Eben nur aufpassen, daß der generierte Code _keine_ festen Adressen (Stringreferenzen o.ä.) enthält.



  • Hem, also theoretisch müsste das gehen. Ich kenne mich leider mit x86-Assembler nicht aus. Aber Pseudocode:

    void load(ifstream &file, size_t filesize)
    {
        std::vector<int> code(filesize);
        std::copy(istream_iterator<int>(file), istream_iterator<int>(), back_inserter(code));
    
        _asm:
            jsr &(code[0]);   // Jump Subroutine
    }
    

    Naja, nicht getestet und nur eine Idee. 😃

    Aber wenn es nicht C++- oder Maschinencode sein soll: eine Scriptsprache wie Python oder LUA erfüllt genau diesen Zweck in C++: Code on the fly ausführen. Ja, sogar on the fly abändern! D.h. ohne das C++-Programm neu starten zu müssen. Machen ja Game-Entwickler auch nicht anders: die ändern ihre Scripte im Spiel und spielen die Scene nochmal neu ohne das Spiel neu starten zu müssen.



  • Ich glaub ich probiers so mal aus 🙂 Python kenne und nutze ich selbst sehr gerne als eingebettete Skriptsprache, ist aber für mein Projekt nicht zu gebrauchen! Aber danke für die Einschätzung des theoretisch-gehens 😉 👍



  • schau dich doch mal bei den jit-compiler (java, mono, perl oder ähnliche) oder bei den vms mit code-umsetzung um (valgrind, virtualbox oder ähnliches). dort solltest du die passende herangehensweise für dein problem finden.



  • Badestrand schrieb:

    Hi!
    Gibts eine Möglichkeit, Code dynamisch einzubinden, außer als DLL? Wenn ich quasi Assembler-Code zur Laufzeit erzeuge oder aus einer Datei lade (nur den Code für eine Funktion), kann ich den irgendwie aufrufen?

    das ist sehr systemspezifisch. unter welcher umgebung möchtest du das machen?
    🙂



  • low level hacker schrieb:

    das ist sehr systemspezifisch. unter welcher umgebung möchtest du das machen?
    🙂

    Unter "normalen" Desktop-PCs, unter Windows und wenn's geht auch unter Linux 🙂 Hab übrigens schon was hingekriegt:

    #include <iostream>
    using namespace std;
    
    typedef void(*Calculator)(int*);
    
    int main()
    {
    	unsigned char code[] = { 0x55, 0x8B, 0xEC, 0x8B, 0x45, 0x08, 0xc7, 0x00, 0x40, 0xE2, 0x01, 0x00, 0x5D, 0xC3 };
    	void* c = (void*)&code[0];
    	Calculator calc = (Calculator)(c);
    
    	int x = 10;
    	calc( &x );
    	cout << x << endl;
    	return 0;
    }
    

    Der Code ist für

    void Calc( int* x )
    {
        *x = 123456;
    }
    

    Im Detail:

    push ebp
    mov ebp,esp
    mov eax, dword ptr [x]
    mov dword ptr [eax],1E240h
    pop ebp
    ret
    


  • Badestrand schrieb:

    Hab übrigens schon was hingekriegt:

    den umweg über den void* kannste dir übrigens sparen. ein

    Calculator calc = (Calculator)code;
    

    sollte reichen. aber bedenke dabei, dass sich der code in einem RAM bereich befindet, der normalerweise nicht für die codeausführung ausgezeichnet ist. manche betriebssysteme könnten darauf etwas zickig reagieren. zu allem übel müsste der code auch noch mit dem selben compiler übersetzt werden, mit dem der code compiliert wurde, der ihn aufruft und wenn erst 'relocation' ins spiel kommt, wird das ganze sowieso gnadenlos abkacken. verwende lieber eine eingebettete skriptsprache (wie schon vorgeschlagen) ansonsten kommst du mit solchen hacks in teufels küche.
    🙂



  • Unter Linux und anderen Unix-Derivaten kannst du mit man: mmap(2) und PROT_EXEC Code direkt ausführbar laden. Achte darauf, dass du den Code Positionsunabhängig kompilierst. Das geht mittels -pie bzw -fPIE-Flag beim GCC.


Anmelden zum Antworten