JIT.au3 - C-Code direkt aus AutoIt kompilieren und ausführen

  • JIT.au3 - C-Code direkt aus AutoIt kompilieren und ausführen

    Manchmal wünscht man sich, dass kritische Teile eines AutoIt-Skripts mit nativer Geschwindigkeit laufen könnten - Schleifen, numerische Algorithmen oder Bit-Operationen, für die AutoIt schlicht nicht gemacht ist. JIT.au3 ermöglicht es, C-Code als String zu schreiben, zur Laufzeit zu kompilieren und direkt aus AutoIt aufzurufen.

    Keine Compiler-Installation nötig. Alles was man braucht ist diese UDF und eine Internetverbindung.
    Die Kompilierung übernimmt die Compiler Explorer (Godbolt) API - der erzeugte Maschinencode wird in ausführbaren Speicher geladen und ist über DllCallAddress aufrufbar.

    GitHub: https://github.com/Sylvan86/autoit-jit-udf
    Download: Releases

    Schnellstart

    Einmal kompilieren, immer wiederverwenden

    Zitat

    Bitte geht respektvoll mit der Godbolt-API um.
    Der Compiler Explorer ist ein freies Community-Projekt. Jeder Aufruf von _JIT_Compile sendet eine Anfrage an deren Server.

    Nach der ersten erfolgreichen Kompilierung kann der Binary-String gespeichert und wiederverwendet werden - keine weiteren API-Aufrufe nötig und deutlich schnellerer Start:

    AutoIt
    ; Erster Lauf: kompilieren und ReusableString notieren
    Global $mCode = _JIT_Compile($sCode)
    ConsoleWrite($mCode.ReusableString & @CRLF)  ; → diesen String speichern
    _JIT_Free($mCode)
    
    ; Alle weiteren Läufe: aus gespeichertem ReusableString laden (kein Internet nötig!)
    Global $mCode = _JIT_LoadBinary('{"b":"8g9YwMM","f":{"doubleIt":0}}')
    Global $aResult = DllCallAddress("double", $mCode.FuncPtr["doubleIt"], "DOUBLE", 21.0)

    Siehe examples/example_reuse.au3 im Repository für eine vollständige Anleitung.

    API-Übersicht

    FunktionBeschreibung
    _JIT_Compile($sCode)C-Code kompilieren und ausführbaren Speicher zurückgeben
    _JIT_LoadBinary($sBinary)Zuvor kompiliertes Binary laden (kein API-Aufruf)
    _JIT_Free($mCode)Ausführbaren Speicher freigeben
    _JIT_SetServer(...)Server, Compiler, Sprache und Proxy konfigurieren
    _JIT_GetCompilers()Verfügbare Compiler auflisten
    _JIT_GetLanguages()Verfügbare Sprachen auflisten
    _JIT_DescribeOpcode($sOp)Beschreibung eines Assembler-Opcodes abrufen

    Einschränkungen

    Diese UDF ist für kleine, eigenständige Code-Snippets gedacht - nicht für vollständige C-Projekte.

    • Keine #include-Unterstützung - die C-Standardbibliothek ist nicht verfügbar. Es gibt keinen Linker; der Code muss vollständig eigenständig sein.
    • Keine math.h-Funktionen - sin(), cos(), pow() usw. benötigen libm, das nicht gelinkt wird. Einige GCC-__builtin_*-Funktionen funktionieren als Inline-Alternativen (siehe examples/example_builtins.au3).
    • Internet für die Kompilierung erforderlich - mit _JIT_LoadBinary kann nach dem ersten Kompilieren offline gearbeitet werden.
    • Einzelne Übersetzungseinheit - der gesamte Code muss in einem String stehen, keine Mehrfach-Datei-Kompilierung.

    Beispiele

    Im Repository sind fünf Beispiele enthalten:

    • example_scalar.au3 - Grundprinzip: eine einfache Funktion kompilieren und aufrufen
    • example_array.au3 - Array an C übergeben: Kahan-Summation vs. naive Summation
    • example_string.au3 - String-Verarbeitung: Groß-/Kleinschreibung im Wechsel
    • example_builtins.au3 - GCC-__builtin_*-Funktionen: was funktioniert, was nicht
    • example_reuse.au3 - Kompilierte Binaries speichern und offline wiederverwenden

    Abhängigkeiten

    • JSON.au3 - JSON-UDF für die API-Kommunikation (im Release-Download enthalten)

    Danksagung

    Dieses Projekt wäre ohne den Compiler Explorer (Godbolt) von Matt Godbolt und Mitwirkenden nicht möglich. Es ist ein großartiges Open-Source-Werkzeug für die Programmier-Community. Bitte nutzt die API verantwortungsvoll.

    8 Mal editiert, zuletzt von AspirinJunkie (11. März 2026 um 10:03)

  • Sehr nice!:klatschen:

    Bin nicht der C(++)-Freak, aber am Testen ^^. Wir waren damals ja an der "direkten" Übermittlung des assemblierten Codes an den Assembler hängengeblieben....

  • Wir waren damals ja an der "direkten" Übermittlung des assemblierten Codes an den Assembler hängengeblieben....

    Genau das!
    Ich konnte die Relokationen schlussendlich auflösen indem ich das ganze zweimal kompiliere (mit unterschiedlichen Parametern) und dort dann die Relocations entsprechend ersetzen kann.
    Das war der Durchbruch.

  • Das ist wirklich beeindruckend 😮 AspirinJunkie , vielen Dank!

    Auch das Compiler Explorer (Godbolt) von Matt Godbolt ist krass.
    Ich finde es auch toll, dass du den Hinweis mit der Godbolt-API gegeben hast (hier und im GitHub Projekt) - sehr weitsichtig - Danke👌.

    Hab' dem Projekt sofort einen ⭐ gegeben und ich mache mich mal damit vertraut.
    Ggf. folgen pull requests - der übliche GitHub Kram. Ob ich Code seitig unterstützen kann, wird sich herausstellen ob ich mich genug einarbeiten kann.

    So oder so, Danke und viele Grüße
    Sven

  • Ich verweise HIER auf den ursprünglichen Thread von AspirinJunkie.

    Mit dem Hintergrund, WIE erfolgreiches Development funktioniert bzw. funktionieren sollte.

    Man MUSS einfach erwähnen, dass es jede Menge teilweise jahrelange Arbeit, Recherche, Schweiß, Geduld, Motivation, Lernbereitschaft, Neugier und viele weitere Eigenschaften braucht, um solch ein Projekt durchzuführen.

    Letztendlich hat es ja geklappt :party:, meinen tiefen Respekt dafür!

  • Mal als Ergänzung: Ich hatte AutoIt allgemein längere Zeit liegen gelassen.
    Aber tatsächlich hat der Einsatz von KI da den Spaß wieder entflammt bei mir.
    Die Idee und technische Umsetzung bekomme ich bei den allermeisten Dingen hin.
    Aber was wirklich abfu**t ist der ganze Scheiß drumherum: Ordentlich formatieren, kommentieren, beschreiben, Codeverwaltung, Beispiele erstellen etc.
    Genau hier ist für mich KI bislang der absolute Game-Changer so dass ich mich jetzt wirklich nur auf den Teil konzentrieren kann der wirklich Spaß macht.

  • Ja, KI kann hilfreich sein, das stimmt.

    Witzigerweise hat gerade ein Kollege einen Artikel (Achtung: Englisch) gepostet was die Nutzung von KI (im allgemeinen) vs. selber umsetzen angeht (Aber den Artikel bitte nicht falsch verstehen):

    Project Overview ‹ Your Brain on ChatGPT – MIT Media Lab
    Check project's website: https://www.brainonllm.comWith today's wide adoption of LLM products like ChatGPT from OpenAI, humans and businesses engage and u…
    www.media.mit.edu

    Falls es wen interessiert. Es ist aber kein Artikel gegen KI, nur es werden durchaus Unterschiede sichtbar.

  • Ich konnte die Relokationen schlussendlich auflösen indem ich das ganze zweimal kompiliere (mit unterschiedlichen Parametern) und dort dann die Relocations entsprechend ersetzen kann.
    Das war der Durchbruch.

    Ich habe am Wochenende damit experimentiert, andere als C++-Compiler via _JIT_Compile() von der godbolt-Website einzusetzen. Funktioniert soweit bei einfachen Beispielen. Btw., die dort verwendeten Tools, u.a. Analysis und die angehängte KI-Erklärung (Claude Explain) und davon vorgeschlagenes Verbesserungspotential sind beeindruckend!

    _JIT_Compile() hat definitiv Potential! Jetzt gibt es kaum noch einen Grund, AutoIt nicht auch für "schnelle" Berechnungen benutzen zu können.


    Ich fände es besser, den C-Code direkt "inline" anzusprechen, wesentlich einfacher zu schreiben und zu debuggen. In AssembleIt hatte ich dazu eine kleine Funktion geschrieben, um den Code bspw. zwischen #cs und #ce schreiben/kopieren zu können.

    vs

  • andere als C++-Compiler via _JIT_Compile() von der godbolt-Website einzusetzen

    Eigentlich gut möglich, jedoch müsste man sich dort das Thema der Relokationen nochmal genauer ansehen. Ich habe das ja durch eine manuelle Ersetzung realisiert. Ob die Bezeichnungen bei den anderen Compilern da gleich sind weiß ich nicht, da ich erstmal nur auf den GCC hin implementiert habe.

    Ich fände es besser, den C-Code direkt "inline" anzusprechen, wesentlich einfacher zu schreiben und zu debuggen.

    Dann bräuchte es aber eine Art Präprozessor der die au3-Datei entsprechend aufarbeitet.
    Das könnte man durchaus als ein Zusatzfeature mit einbauen.
    Ansonsten teile ich aber deine Grundproblem mit den Multi-Line-Strings in AutoIt: die sind einfach Mist.

  • Nette Idee :thumbup:

    Kann jemand mal testen?

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    8 Mal editiert, zuletzt von UEZ (9. März 2026 um 19:54)

  • Kompiliert ergibt das folgendes:

    AutoIt
    Global $sBinary = @AutoItX64 _
                      ? '{"b":"RYXAD46DAAAAQVRVV1aJ1lOF0n5wSInLRInHMclFMcBMY9pmZi4PH4QAAAAAAGaQRInARI0UiTHSTI0Mgw8fAInNjQRSMdVEMdBBiewPtsDB5QdBweQQgeUA/wAAQYHkAAD/AEQJ4AnoDQAAAP9BiQSRSIPCAUk503XFg8EBQQHwOc91q1teX11BXMPD","f":{"XorTexture":0}}' _
    				  : '{"b":"VVdWU4PsBItUJCCF0n5xi0QkHIXAfmmLRCQci3wkGDH2jRyFAAAAAIkcJC6NdCYAjSy2MdIujbQmAAAAAI12AInRjRxSMfEx64nID7bbweEHweAQgeEA/wAAJQAA/wAJ2AnIDQAAAP+JBJeDwgE5VCQcdcyDxgEDPCQ7dCQgdbCDxARbXl9dwgwA","f":{"XorTexture":0}}'
    Global $mCode = _JIT_LoadBinary($sBinary)

    Kompilieren klappt aber dann passiert nicht viel bei mir.

    Vielleicht kann man ein Proxy mitgeben...

    Kann man:

    AutoIt
    #include "JIT.au3"
    $oHTTP.SetProxy(2, "localhost:3128")

    2 Mal editiert, zuletzt von AspirinJunkie (9. März 2026 um 18:55)

  • Bekomme mit den Binärstrings:
    !>14:41:06 AutoIt3 ended. rc:-1073741819 -> Speicherschutzfehler.

    Ist der Aufruf so korrekt? -> Global $aDll = DllCallAddress("none", $mCode.ptr + $mCode.Funcs["XorTexture"], "ptr", DllStructGetPtr($pScan0), "int", $iW, "int", $iH)


    $oHTTP.SetProxy(2, "localhost:3128")

    kann doch nicht funktionieren, da $oHTTP doch lokal in den Funktionen definiert wird, oder?

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Ich hatte die UDF vor nicht all zu langer Zeit aktualisiert. Schau also mal ob du die aktuelle Version hast.
    Hatte das so umgestellt, dass man direkt die Offsets der Funktionen mit als String erhält und die nicht extra erfassen muss.

    $oHTTP.SetProxy(2, "localhost:3128")

    kann doch nicht funktionieren, da $oHTTP doch lokal in den Funktionen definiert wird, oder?

    Doch - ist ne globale. Genau so verwende ich es auch ab und an - daher bin ich mir äußerst sicher, dass das funktioniert (mit NTLM geht es aber glaube ich nicht).

  • $__g_JIT_oHTTP ist Global, aber nicht $oHTTP - wird immer local in der Funktionen definiert.


    Meinst du vielleicht?:


    $__g_JIT_sProxy = "localhost:3128"

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • klappt bei mir

  • und so mit dem binary

    den bekommt man nach dem $mCode = _JIT_Compile($sSourceCode)mit $mCode.BinaryString


    //EDIT

    Mit der Compileroption -O3 wird zwar mehr (assembler-)code erzeugt, der läuft dafür aber 2,5x schneller!

    Global $mCode = _JIT_Compile($sSourceCode,"-O3")

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    4 Mal editiert, zuletzt von Andy (9. März 2026 um 17:02)

  • den bekommt man nach dem $mCode = _JIT_Compile($sSourceCode)mit $mCode.BinaryString

    Das ist die "alte" Variante. Hier muss man sich aber selbst um die Offsets für die Funktionen kümmern.
    Da es hier nur eine Funktion gibt ist das aber nicht schädlich (und auf die Art sogar einfacher und kürzer).
    Aber allgemein rate ich nun dazu, stattdessen den String $mCode.ReusableString zu verwenden - dann liefert _JIT_LoadBinary() auch $mCode.Funcs.
    _JIT_LoadBinary() versteht beide Varianten.


    Ansonsten klappt bei mir Andys Version ebenso. Sieht wieder einmal äußerst schick aus :thumbup:

  • Ok ich habe soeben eine Änderung ins Repository gepusht: Die Binary-Strings im ReusableString sind ab sofort Base64-kodiert statt Hex-kodiert. Das macht sie kürzer was vor allem beim Einfügen in den Quellcode besser ist.
    Wie gesagt: Dazu muss man aber die neueste Version verwenden.