Assemblerfunktion zum Aufsummieren direkt in AutoIt

  • Zugegeben - bedeutend schlauer bin ich nicht noch nicht wirklich.

    ; ist das die Größe des 1. Parameters in Bytes?
    $a=4
    ;nein, das ist der Parameter, der Integer der quadriert werden soll

    Ok mich hatte an der Nummer verwundert, dass man die Werte bereits beim Erstellen des Codes einträgt. Wenn ich das aber richtig verstehe, geht es darum, dass man die Debugging-Funktionalität damit nutzen kann?

    Traumziel wäre ein JIT-Compiler für derartige Sachen in AutoIt.
    Aktuell stehe ich aber noch vor dem Problem, dass du ein Opcode vom Kompilat des gcc-Compilers ausgetauscht hast und ich (mangels ASM-Kenntnisse) nicht weiß warum das nötig ist.
    Momentan sieht mein Grundgerüst auf Grundlage deiner Skripte folgendermaßen aus:

    Eventuell kannst du Licht ins Dunkel bringen in welchen Fällen das versagt und in welchen es klappt und was dazu immer notwendig ist.

    2 Mal editiert, zuletzt von AspirinJunkie (9. September 2024 um 08:39)

  • Hi,

    sorry für die späte Antwort.

    Eventuell kannst du Licht ins Dunkel bringen in welchen Fällen das versagt und in welchen es klappt und was dazu immer notwendig ist.

    "Es" funktioniert in allen Fällen in denen der Compiler in der Lage ist, ohne einzubindende Module (ASM-)Code zu erzeugen. Ich bin mir sogar sicher dass funktionsfähiger Code entstehen würde, wenn du bspw. die SQRT()-Funktion aus der Bibliothek herauslösen würdest und in den Quellcode einbindest. Für den Quellcode

    Code
    '#include <math.h>' & @LF & _
    'double squareroot(double num) {' & @LF & _
    '    return sqrt(num);' & @LF & _
    '}'

    wird folgender ASM-Code erzeugt

    Code
    push   rbp
     mov    rbp,rsp
     sub    rsp,0x10
     movsd  QWORD PTR [rbp-0x8],xmm0
     mov    rax,QWORD PTR [rbp-0x8]
     movq   xmm0,rax
     call   1b <squareroot+0x1b>
        R_X86_64_PLT32 sqrt-0x4
     leave
     ret

    der "call 1b" ruft die Unterfunktion an der Adresse 1b im Code auf, das ist allerdings genau die nächste Zeile mit dem "leave", was den Rücksprung aus der Funktion aufruft. Wie du bereits vermutet hast, wird der Call in die Unterfunktion ausgeführt, aber infolge fehlendem Code nicht ausgeführt.

    Was bereits bemerkenswert ist, ist die Tatsache, dass du "fast" lauffähigen Assemblercode aka Opcodes erzeugen kannst.

    Ich habe mal etwas mit dem gcc auf godbolt experimentiert. **ToDo**Ggf. sollte man per AutoItscript einen "echten" gcc oder anderen Compiler lokal steuern und die Opcodes disassemblieren....

    Der vom godbolt erzeugte ASM-Code stellt ausschliesslich das 1:1-pendant des C(++)-Codes dar! Da wird keinerlei "Struktur" mitassembliert! Will heißen:

    Eine C-Funktion main() (oder andererer Funktionsname), welcher KEINE andere Funktion aufruft, wird, wie von dir demonstriert, anstandslos ausgeführt.

    Wird allerdings in main() eine andere Funktion (bspw. add())aufgerufen, muss diese vor main() deklariert werden. Der C-Compiler "weiß", dass die add()-Funktion eine Funktion ist und springt im Compilat zu main(), arbeitet den dortigen Code bis zur Funktion add() ab, springt in add(), von dort zurück in main() und beendet das Programm....

    Im von godbolt erzeugten ASM-Code wird "einfach" eine Funktion add() erzeugt und eine Funktion main()

    Sourcecode:

    Code
    int add(int num) {
        return num + num;
    }
    
    
    int main() {
    int b = 5;    
    int a = add(b);
    return a;
    }

    Daraus macht godbolt:

    dieser Code hat aber ein Problem. Wenn assembliert, startet der code bei add() und wird beim nächsten ret beendet. main() wird NIE aufgerufen.

    Würde main() VOR den anderen Funktionen stehen, so wie hier (und die (int)´s im code entfernt werden), so dass folgender Code entsteht

    dann wird dieser code anstandslos assembliert (u.a. von AssembleIt, aber auch bei https://defuse.ca/online-x86-assembler.htm#disassembly)

    0x554889E54883EC10C745FC050000008B45FC89C7E8080000008945F88B45F8C9C3554889E5897DFC8B45FC01C05DC3

    und ist lauffähig (ACHTUNG! AssembleIt benutzt den FASM-Assembler, und der reagiert allergisch darauf, wenn man "call add" aufruft. add ist eine Assembler- Anweisung, benennt man die Funktion bzw. Adresse im Code in "addieren" um, funzt alles problemlos^^). Der Disassembler https://defuse.ca/online-x86-assembler.htm#disassembly assembliert zu


    der call-befehl ruft die Funktion add an der Adresse 21 auf (FASM macht das genau so....JEDER Assembler generiert die gleichen OpCode:

    0x554889E54883EC10C745FC050000008B45FC89C7E8080000008945F88B45F8C9C3554889E5897DFC8B45FC01C05DC3

    welcher auch das "richtige" Ergebnis liefert: (AutoIt-Code hier von AssembleIt erzeugt)

    Code
    Local $aStructMem = DllCall("kernel32.dll", "ptr", "VirtualAlloc", "ptr", 0, "ulong_ptr", DllStructGetSize(DllStructCreate("byte[47]")), "dword", 4096, "dword", 64)
    Local $tCodeBuffer = DllStructCreate("byte[47]", Number($aStructMem[0]))  ;Address aligned 64 and Memory is  $MEM_COMMIT, $PAGE_EXECUTE_READWRITE
    DllStructSetData($tCodeBuffer, 1,"0x554889E54883EC10C745FC050000008B45FC89C7E8080000008945F88B45F8C9C3554889E5897DFC8B45FC01C05DC3") ;write opcodes into memory
    $ret=DllCallAddress("int:cdecl", DllStructGetPtr($tCodeBuffer))
    
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret[0] & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    Zur Vollständigkeit halber der AssembleIt-Code:


    Zusammengefasst:

    Du bist mit deinem Programm bei ca. 90% Funktionalität angelangt. Ganz ohne Nachbearbeitung des vom Godbolt-gcc (oder von anderen Compilern) erzeugten Codes geht es zzt. noch nicht. Btw. habe ich sowohl die von UEZ als auch die von Kanashius erzeugte ASM-Codes mit AssembleIt lauffähig bekommen, allerdings mit "Nachbearbeitung".

    Bei der Erstellung einer DLL werden Bibliotheken bzw. die darin enthaltenen und im Code benötigten Funktionen dazugelinkt.

    Aber wo ist das Problem, aus bspw. C(++) - Bibliotheken die einzelnen Funktionen zu assemblieren und später an dein Programm "anzuhängen".

    Man hätte den Vorteil, dass man nur noch ca. 5% des ASM-Codes schreiben bzw. rudimentär ändern müsste, um ein extrem schnelles Programm in AutoIt zu erhalten.....schreib mal einige Zeilen C(++)-code oder mit einem anderen Compiler und wir sehen weiter.

    Oder schon fortgeschritten: Gib mit den disassemblierten, also ASM- Code einer von dir benötigten Matrix-Funktion (bspw. von einem x-beliebigen Compiler generiert), und ich sehe zu, dass ich dazu die passenden Opcodes erstelle....


    Dieses Projekt würde den "AutoItcompiler" fast überflüssig machen....

    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

    9 Mal editiert, zuletzt von Andy (10. September 2024 um 21:22)

  • Man kann auch die DLLs in das Skript integrieren (Base64) und per MemCall() aufrufen, somit würde das Weitergeben der DLL entfallen. Rust scheint ja echt kleine DLLs im Gegensatz zu Freebasic zu generieren, sodass das Integrieren nicht unnötig den Code aufbläht. Freebasic ist anscheinden wie mein Bauch...;)

    Das Aktualisieren wäre sicherlich auch einfacher, als mit dem ASM Code.

    Andy kleine Doktorarbeit zum Thema Assembler gepostet :thumbup:

    Ich persönlich vergesse sehr schnell das Programmieren in ASM und mir fällt es schwer wieder rein zu kommen. Bei dir ist das anscheinend in Fleisch und Blut übergegangen. :)

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Bei dir ist das anscheinend in Fleisch und Blut übergegangen. :)

    Naja, du weisst ja wie das ist, man kann einem alten Hund keine neuen Tricks beibringen....braucht man aber auch nicht, seit dem allerersten Prozessor (na gut, x86-Prozessor also der 8086) ist der ASM-Code absolut unverändert. Einige Erweiterungen (x64,SSE,AVX uswusf.) sind dazugekommen und einige Handvoll neuer Prozessorbefehle, aber der "Ablauf" im ASM-Code ist wie vor 40 Jahren....da gibts nix "neues", also muss ich auch keine neuen Tricks lernen:party:.

    Das Aktualisieren wäre sicherlich auch einfacher, als mit dem ASM Code.

    Bin ich voll und ganz dabei. Wenn die Compiler nur nicht so schrecklich "doof" wären....aber das liegt sicherlich an mir....ich habe Compilate disassembliert, da fliegt dir der Hut weg! Derart schnellen und GEILEN ASM-Code bekommen nicht mal die besten Assembler-Cracks geschrieben....und das nur mit einigen Zeilen (zugegeben auch GUTEM) Hochsprachencode und F5 drücken.....

    In einigen anderen Beiträgen zu ähnlichen Themen habe ich schon geschrieben, wie ich mich mit den Jungs und Mädels im Forschungszentrum Jülich und deren HPC-Anwendungen und Optimierungen beschäftigt habe. DAS ist die obere Spitze vom Eisberg....da schreibt niemand irgendwelchen Larifaricode, ohne zu wissen bzw nachzuprüfen, was der Compiler daraus macht. Wenn in einen Rechencluster mehrere hundert Millionen Euro versenkt werden, dann nicht, um nur 5-10% von der Rechenleistung auszunutzen...schon 90% sind zu wenig!!!

    Wie ich schon immer postuliert habe: langsamer Code ist und bleibt langsam, selbst mit einem schnellen Compiler compiliert! "Schneller" Code ist die Ausnutzung ALLER im Prozessor (egal ob CPU oder GPU) integrierten Komponenten und Rechenwerke. Da in Jülich auch mit OpenCL gearbeitet und entsprechend optimiert wurde, hat mir das auch bei schnellen Berechnungen auf meiner Grafikkarte geholfen. Die kostet nur die Hälfte von meinem Prozessor, ist aber in der Lage bestimmten Code x-mal schneller auszuführen....

    S. Beispiel oben. Freebasic und Rust compilieren Code, der von einigen Bytes ASM-Code um mehrere Faktoren abgehängt wird! Da können aber die Compiler nix dafür, das hängt am Sourcecode! Nur weil ich weiß, dass man statt 4 Zahlen nacheinander zu addieren das auch in EINEM Prozessorbefehl machen kann, bin ich ja kein Crack....wenn ich mich "früher" statt mit Assembler mit C beschäftigt hätte, würde ich sicher auch SSE- und AVX-Code in C schreiben können. Oder in einer anderen Compilersprache...aber ich bin halt bei "Basic" hängengeblieben...und Assembler :theke:

  • Btw. Vektorisierung...für Rust habe ich etwas gefunden: https://www.heise.de/hintergrund/Ta…15.html?seite=2

    "Fast" gleicher Quellcode, aber 4x schneller....

    Leider gibt es für Freebasic keine Vektorisierung, oder ich habe keine gefunden...

    //EDIT

    So wie ich das mittlerweile sehe, führt bei Vektorisierung kein Weg an hochoptimierten Libs oder Bibliotheken vorbei. AspirinJunkie , ggf. solltest du doch über den Vorschlag von UEZ nachdenken und eine dieser Libs integrieren und die Funktionen darin aufrufen....:Glaskugel:

    //EDIT2

    ....ich schreibe dir aber gerne auch eine kleine und feine ASM-Funktion:saint:

    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

    2 Mal editiert, zuletzt von Andy (10. September 2024 um 22:59)

  • "Es" funktioniert in allen Fällen in denen der Compiler in der Lage ist, ohne einzubindende Module (ASM-)Code zu erzeugen. Ich bin mir sogar sicher dass funktionsfähiger Code entstehen würde, wenn du bspw. die SQRT()-Funktion aus der Bibliothek herauslösen würdest und in den Quellcode einbindest.

    Ja da bin ich mir auch sicher. Allerdings hab ich mir mal den Quellcode für sqrt() in den Standardbibliotheken angesehen - das ist richtig viel Code, welcher auch wieder etliche Nebenabhängigkeiten mitbringt.
    Allerdings war die sqrt-Geschichte ein schlechtes Beispiel. Dafür gibt es ja bereits eigene CPU-Befehle und als ich diese per intrinsics aufgerufen habe (Assemblerbefehl "sqrtsd"), konnte ich auch mit dem godbolt-Code hier eine Funktion mit Wurzel schreiben die funktionierte.

    Mein Problem liegt derzeit noch an einer anderen Stelle: Ich schaffe es nicht Pointer zu übergeben um ein Array abzuarbeiten.
    Folgendes Beispiel läuft bislang nicht bei mir:

    Aber wo ist das Problem, aus bspw. C(++) - Bibliotheken die einzelnen Funktionen zu assemblieren und später an dein Programm "anzuhängen".

    Ja eben wo ist das Problem?
    Braucht man dafür einen Fluxkompensator?
    Die sqrt-Funktion z.B. mal eben rauszulösen ist nicht ohne, da sie ziemlich aufwendig gestaltet ist und selbst wiederrum haufenweise weitere Abhängigkeiten mitbringt.
    Ich denke im ersten Schritte würde es ja reichen erst einmal eigene unabhängige Funktionen lauffähig zu bekommen.
    Aber da komme ich ja schon wie gesagt (siehe Pointer-Geschichte oben) nicht weiter.

    dieser Code hat aber ein Problem. Wenn assembliert, startet der code bei add() und wird beim nächsten ret beendet. main() wird NIE aufgerufen.

    Die Funktion _ce_compileCode() gibt eine Map zurück. Dort findet sich auch der Eintrag ["Funcs"].
    Das sind die benamten Funktionen im Assemblercode mit ihren Start-Offsets als Value.
    Man kann also auch mehrere Funktionen kompilieren und dann über ihre Offsets in DllCallAddress einzeln ansprechen.
    Bei Verweisen im Code zwischen den Funktionen müsste man wahrscheinlich dann aber noch die Call-Aufrufe entsprechend anpassen, da die Sprungadresse beim Call noch nicht feststeht(?).
    Nur die Main-Funktion lasse ich explizit aus dem Ergebnis verschwinden, da ich diese für meinen Anwendungsfall ja nicht brauche.

    Man kann auch die DLLs in das Skript integrieren (Base64) und per MemCall() aufrufen, somit würde das Weitergeben der DLL entfallen.

    Klingt mir sehr zielführend und effizient.
    Ich dachte wir hätten uns aber auf den komplizierten, instabilen und umständlichen Weg geeinigt?... ;)

    Ne das wäre sicherlich tatsächlich ein sehr gangbarer Weg, welchen ich auch mal probieren werde (und evtl. als finalen Ansatz für mein Projekt verwende).
    Aktuell ist das mit dem Binary-Code aber nicht lebensnotwendig, so dass ich das gerade als Anlass für Spielereien sehe.
    Ein in AutoIt eingebauter C-Compiler wäre schon fein wenn das als "Abfallprodukt" hinten raus fällt.

    Aber zu der Rust-Dll-Geschichte: Eh ich erst einmal selbst wieder auf Recherchejagd gehe: Hast du da vielleicht gleich online Dokus wie man mit Rust entsprechende Dlls erstellt und evtl. sogar in AutoIt per MemCall einbindet?

  • Außerdem hat sich Ward 2015 aus dem Forum verabschiedet und allen geposteten Code gelöscht :(

  • Zitat

    Aber zu der Rust-Dll-Geschichte: Eh ich erst einmal selbst wieder auf Recherchejagd gehe: Hast du da vielleicht gleich online Dokus wie man mit Rust entsprechende Dlls erstellt und evtl. sogar in AutoIt per MemCall einbindet?

    Ich hab für die QRCode UDF (QRCode UDF) mit Rust einen .dll erstellt. Wenn ich UEZ richtig verstanden habe, dann müsstest du die Base64 encoden und kannst die dann mit MemCall laden?

    Was du auf der Rustseite machen musst:

    Cargo.toml ([lib] section, damit eine windows .dll erstellt wird; [profile.release] kram ist für das optimizationlevel => kleinere Dateigröße):

    Code
    [lib]
    crate-type = ["cdylib"]
    
    [profile.release]
    codegen-units = 1
    lto = "fat"

    Code als C markieren (Damit structs, functions,... wie in C angelegt werden und kompatibel sind) e.g.:

    Code
    #[repr(C)]
    pub struct QRCode {
        pub something: u8, // ...
    }
    
    #[no_mangle]
    pub extern "C" fn EncodeText(input: *const u8, size: u32, ecl: u8, result: *mut QRCode) -> u8 { /* ... */}

    Mit target und als release kompilieren (beim erstenmal kann nen fehler kommen, dass du alles fürs build für das target erst installieren musst (je nachdem, auf was für einem system du bist), der command steht da aber auch direkt):

    Code
    x86: cargo build --target=x86_64-pc-windows-msvc --release
    x64: cargo build --target=i686-pc-windows-msvc --release


    Das sollte eigentlich alles sein :)

  • Mein Problem liegt derzeit noch an einer anderen Stelle: Ich schaffe es nicht Pointer zu übergeben um ein Array abzuarbeiten.
    Folgendes Beispiel läuft bislang nicht bei mir:

    Ja, der Fehler liegt aber nicht bei dir, sondern bei godbolt bzw. den calling conventions des gcc.....das war mir schon bei den ersten Beispielen mit Funktionen mit Parametern aufgefallen.

    Exkurs in Calling conventions: https://en.wikipedia.org/wiki/X86_calli…ing_conventions

    Kurz zusammengefasst bestimmen die calling conventions, wie die Funktionsparameter an den ASM-Code übergeben werden.

    Wenn man sich den Anfang des ASM-Code anschaut

    Code
     push   rbp
     mov    rbp,rsp
     mov    QWORD PTR [rbp-0x18],rdi
     mov    DWORD PTR [rbp-0x1c],esi

    dann sieht man, dass die ersten beiden Parameter der Funktion die Register rdi (64 bit, die Adresse der Struct der zu addierenden doubles) und esi (32Bit, 5 Doubles sollen addiert werden) sind

    esi ist der niedrige Teil des rsi - Registers

    Die ersten beiden Parameter werden also in den Registern RDI und RSI übergeben....schaut man sich die calling conventions an, dann ist das

    Code
    System V AMD64 ABI
    The calling convention of the System V AMD64 ABI is followed on Solaris, Linux, FreeBSD, macOS,[26] and is the de facto standard among Unix and Unix-like operating systems. The OpenVMS Calling Standard on x86-64 is based on the System V ABI with some extensions needed for backwards compatibility.[27] The first six integer or pointer arguments are passed in registers RDI, RSI, RDX, RCX, R8, R9 (R10 is used as a static chain pointer in case of nested functions[28]: 21 ), while XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6 and XMM7 are used for the first floating point arguments.

    Unix-gedöns....gcc....wtf....:P

    Schau mal, ob du bei godbolt einen Compiler für Windows findest oder die calling conventions umstellen kannst...

    Ich habe im von godbolt erstellten ASM-Code das register esi durch edx ersetzt und damit die Microsoft x64 calling convention erfüllt, der gcc kann das auch!!

    Damit läuft dein Code:

    Wenn die Calling conventions vom aufrufenden Programm und der Funktion übereinstimmen, dann fluppt es :o)


    //EDIT

    habs gefunden:

    __attribute__((ms_abi))

    Im c++-code des gcc erstellt code der Microsoft x64 calling convention

    Code
    Global $sSourceCode = _
    '__attribute__((ms_abi))' & @LF & _
    'double sumArray(double *arr, int size) {' & @LF & _
    '    double sum = 0.0;' & @LF & _
    '    for (int i = 0; i < size; i++) {' & @LF & _
    '        sum += arr[i];' & @LF & _
    '    }' & @LF & _
    '    return sum;' & @LF & _
    '}'

    funzt!!!!

    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

    2 Mal editiert, zuletzt von Andy (11. September 2024 um 19:17)

  • Na das bringt mich schonmal ein großes Stück weiter.
    Versuchen wir doch mal das ganze etwas zu strukturieren und leichter zugänglich zu machen.
    Hierzu habe ich das mal als rudimentäre UDF verpackt - nennen wir die Datei einfach mal "JIT.au3":


    Wenn wir das haben können wir das ganze folgendermaßen verwenden um Code zu kompilieren und anschließend auszuführen (auch der Zugriff auf mehrere Funktion wird hier gezeigt):


    Natürlich wollen wir nicht jedesmal neu kompilieren, also macht es Sinn sich einmalig den Binary-String z.b. so zu erzeugen:


    Und dann fortan folgendermaßen zu verwenden:


    Für mich sieht das schon ziemlich rund aus - was meint ihr dazu?


    Kanashius Vielen vielen Dank schon mal für deine Erläuterungen.
    Das werde ich mir mal in Ruhe zu Gemüte führen.
    Wird aber sicherlich ein bisschen dauern, da ich ja nun durch die Geschichte hier mehrere Hochzeiten habe auf denen ich tanzen möchte.

    2 Mal editiert, zuletzt von AspirinJunkie (12. September 2024 um 11:53)

  • Für mich sieht das schon ziemlich rund aus - was meint ihr dazu?

    Nicht nur ziemlich rund...das ist schon fast perfekt.

    Ich würde, wie in AssembleIt, den Sourcecode "lesbar" zwischen irgendwelche #cs- und #ce-Tags packen, dann hat man die Hochkommas und das '&@LF&_-gedöns nicht mehr, kann den Code einrücken und auch kommentieren.

    Der ASM-Code ist ggf auch ganz nützlich um zu debuggen/Code zu optimieren. Ich habe mich mal etwas mit den Intrinsics befasst, AVX512 und die Prozessorbefehle "neuer" Prozessoren" sind schön mit C++ und der CPUID abzufragen, wie bspw. hier gezeigt https://en.algorithmica.org/hpc/simd/intrinsics/

    Solltest du vorhaben, "große" Matritzen zu multiplizieren bzw. zu berechnen, sollten SSE/AVX-Befehle verwendet werden. Ist nicht schwer und Faktor 3-6 schneller, je nach Anforderung bzw. Aufgabenstellung und Befehlsauswahl sind auch noch einige Faktoren mehr drin. FMA benutze ich auch gerne wenn es passt...https://de.wikipedia.org/wiki/Fused_multiply-add und https://de.wikipedia.org/wiki/FMA_x86

    Hmmmm..... $oHTTP.SetProxy(2, "localhost:3128") funktioniert nur bei deinem Proxyserver

  • Nicht nur ziemlich rund...das ist schon fast perfekt.

    Hm nein leider noch nicht.
    Aktuell habe ich ein Problem bei der Behandlung von Gleitkommakonstanten und damit allen Berechnungen die mit denen gemacht werden (z.b. das Reziproke bilden).
    Hier mal am Beispiel:

    Meine Vermutung ist, dass ich den gcc unter Linux anspreche und evtl. hier noch Unterschiede in der Behandlung von Gleitkommazahlen zwischen Linux und Windows existieren.
    Darüber hinaus klappt das Beispiel hier auch nicht mit der 32-Bit-Variante - warum auch immer.
    Ich wollte daher mal einen Windows-basierten Compiler stattdessen verwenden - mingw gcc oder msvc - aber die bekam ich mit der API hier bislang nicht zum laufen - immer kein Response.
    Also spiele ich gerade mit den gcc-Parametern -mabi=ms -mrtd herum um die CALLCONV-Geschichte zu umgehen.

  • //EDIT....Post unvollständig

  • Meine Vermutung ist, dass ich den gcc unter Linux anspreche und evtl. hier noch Unterschiede in der Behandlung von Gleitkommazahlen zwischen Linux und Windows existieren.
    Darüber hinaus klappt das Beispiel hier auch nicht mit der 32-Bit-Variante - warum auch immer.

    nein, glaube ich nicht.

    "If you want to know how it works, read the code!"

    Der C(++) Code ist ja "richtig". Wenn das Ergebnis nicht stimmt, dann muss zwangsläufig der ASM-Code "falsch" sein. Da scheint es daran zu liegen...

    Wenn ich diese C-Zeilen in den Godbolt eingebe:

    Code
    double test() {
        return 5.8;
    }

    erhalte ich im browser im godbolt mit dem gcc 14.2 den asm-code

    Code
    test:
            movsd   xmm0, QWORD PTR .LC0[rip]
            ret
    .LC0:
            .long   858993459
            .long   1075262259

    (die beiden .long sind die 8 Bytes double für die Zahl 5.8)

    was, umgeschrieben in FASM-Syntax und mit AssembleIt assembliert, einwandfrei funktioniert:

    Ist auch logisch, wenn man sieht, was der ASM-Code da macht. 8 Bytes aus dem Speicher ab Offset .LC0 ins Register XMM0 schreiben und fettich.....

    opcodes aka binary dazu:

    Code
     0xF20F100501000000C33333333333331740

    Wenn der C-code über JIT.AU3 an godbolt gesendet wird, erhalte ich von dort

    Code
    @@ Debug(81) : $sASMCode = test:
     movsd  xmm0,QWORD PTR [rip+0x0]        # 8 <test+0x8>
        R_X86_64_PC32 .LC0-0x4
     ret
    
    >Error code: 0
    @@ Debug(87) : $sBinary = f20f100500000000c3

    die binary disassembliert wird zu

    Code
    0:  f2 0f 10 05 00 00 00    movsd  xmm0,QWORD PTR [rip+0x0]        # 0x8
    7:  00
    8:  c3                      ret

    Was man sofort sieht, WO IST DIE KONSTANTE?

    Imho liegt es also nicht am godbolt und/oder dem compiler dort, sondern an deiner HTTP-Anfrage und dem entsprechenden response...


    //EDIT

    es hängt am flag "compile to binary object"

    ist das gesetzt, compiliert der Compiler (opcodes aka binary sind falsch) und disassembliert den code, was zum o.g. "falschen" Ergebnis und ASM-Code führt...8|

    Ist das flag nicht gesetzt, dann wird zwar der ASM-Code "richtig" erzeugt (woher ist jetzt die Frage?!) aber es fehlen die Opcodes im respose:/

    Ich habe es nicht geschafft, die flags so einzustellen , dass der "richtige" ASM-Code zusammen mit den dazugehörigen Opcodes zurückkommt

    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

    Einmal editiert, zuletzt von Andy (14. September 2024 um 14:47)

  • Hui, das sind ja schonmal starke Hinweise wo man suchen muss.
    So wie ich das Problem verstehe haben wir das Problem, dass wenn man sich das binary auch zurückgeben lässt, der gcc für die Konstanten Relokationen erstellt.
    Sprich: Wo der Wert 5.8 mal stehen wird ist beim Kompilieren noch nicht klar. Erst der Linker muss das, wenn alle Codeteile vorliegen, entsprechend auflösen.
    Nun haben wir jedoch das Problem, dass bei compiler explorer gar kein Linker zum Einsatz kommt.
    Die Relokationen bleiben also bestehen.

    Es gibt zwar flags mit denen sich bestimmte Relokationen vermeiden lassen.
    Die haben hier aber bei mir nicht zum Erfolg geführt.
    Jetzt bin ich bisschen ratlos zugegeben.
    Die Alternative wäre ja wirklich kompilieren + linken.
    Schade - compiler explorer mit der simplen API wäre schon schick gewesen.

  • Die Alternative wäre ja wirklich kompilieren + linken.

    Ja, ich bin mir sicher, wenn man etwas in den Eingeweiden von godbolt wühlt, dann gibt es dort genau solche Möglichkeiten.

    Der "richtige" ASM-Code ist ja da! Ggf. gibt es die Möglichkeit, diesen direkt über den Linker in ein binary zu überführen.

    Hier https://stackoverflow.com/questions/1647…tput-raw-binary habe ich etwas dazu gefunden

    Code
    So when compiling with gcc if you pass -Wl,--oformat=binary you will generate a binary file instead of the elf format. Where --oformat=binary tells ld to generate a binary file.

    Der Compiler und der Linker werfen dabei keinen Fehler, wenn ich das auf der Website nutze.

    Bestimmt hat man die Möglichkeiten, eine .bin-Datei statt der .s-Datei (ASM-Code) zu erstellen und herunterzuladen.

  • Also wenn ich mal auf einem lokalen gcc folgendes ausführe:

    Code
    gcc -m64 -O3 -mabi=ms -Wl,--oformat=binary -c test.c -o binary.bin

    enthält die binary.bin entgegen der Aussage dort immer noch Daten im ELF-Format. Auch der darin enthaltene Binary-Code entspricht nicht dem gewünschten Code sondern dem problematischen.

    Wenn ich hingegen die manuelle Kaskade durchlaufe:

    Code
    gcc -m64 -O3 -mabi=ms -c test.c -o test.o
    objcopy --only-section=.text --output-target binary test.o binary.bin

    erhalte ich wieder unser vorheriges problematisches Ergebnis mit den unaufgelösten Relokationen. (per objdump --disassemble test.o schön zu sehen)

    Vielleicht versuche ich es mal mit der Dll-Variante und versuche die relevanten Binaries dort anschließend herauszulösen (oder ich versuche diese Memcall-Methode).

  • Ich teste gerade diverse Assembler g++ usw.

    Ich kann in keinster Weise nachvollziehen, wo das Problem ist, den asm-code eins zu eins in die Opcodes zu überführen...jeder fu**ing 50 Jahre alte Assembler kann das.

    Vielleicht versuche ich es mal mit der Dll-Variante und versuche die relevanten Binaries dort anschließend herauszulösen (oder ich versuche diese Memcall-Methode).

    hehe, genau DAS hatte ich auch vor, Problem dabei ist, du musst die DLL disassemblen um den Einsprungpunkt in die einzelnen Funktionen zu finden....

    Nein, der Ansatz mit einem Assembler, der gcc-asm-code assembliert, ist wesentlich einfacher