Assemblercodes für das neue X4

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • Assemblercodes für das neue X4

      Ein erste Minimal-Assembler-Programm zum Addieren zweier Zahlen:

      Quellcode

      1. CLS
      2. ASM "MeineFunktion", 2
      3. mov eax,par1
      4. mov ebx,par2
      5. add eax,ebx
      6. ENDASM
      7. Var Long Ergebnis = MeineFunktion(38764, 879879878)
      8. Print Ergebnis
      9. Print "Fertig!"
      10. WaitInput
      Alles anzeigen

      Die Zahl hinter dem Funktionsnamen gibt die Anzahl der Parameter an. Diese ist wichtig, damit nach dem Aufruf korrekt "aufgeräumt" wird. Im Debug-Modus, der derzeit im Interpreter noch fix eingestellt ist, wird ein Assemblerlisting für jede ASM-Funktion ausgegeben. Der Dateiname ist der Funktionsname mit der Endung "lst". Dieses Listing sieht hioer so aus:

      Quellcode

      1. MeineFunktion - 2
      2. 0000 55 PUSH ebp
      3. 0001 89E5 MOV ebp,esp
      4. 0003 8B4508 MOV eax,par1
      5. 0006 8B5D0C MOV ebx,par2
      6. 0009 01D8 ADD eax,ebx
      7. 000B 89EC MOV esp,ebp
      8. 000D 5D POP ebp
      9. 000E C20800 RET 8
      10. 5589E58B45088B5D0C01D889EC5DC20800
      Alles anzeigen

      Das zwingend notwendige "PUSH EBP" und "MOV EBP,ESP" am Anfang, sowie das "MOV ESP,EBP" und "POP EBP" und das "RET x" fügt XProfan selbsttätig hinzu. Vom ESP-Register (Stack) sollte man auf alle Fälle im Code die Finger lassen!

      Par1 steht für [ebp + 8] (die Speicherstelle an der der erste Parameter abgelegt wird), Par2 für [ebp + 12], etc. Da wir uns in der 32-Bit-Welt befinden hat jeder Parameter eben 4 Byte! Der Wert in EAX ist der Rückgabewert der Funktion.

      Der ASM-Befehl assembliert den nachfolgenden Code bis ENDASM und fügt die Funktion der Liste der importierten Funktionen bei, so wie es auch ImportDLL und ImportFunc machen. Anschließend steht die Funktion dem Programm zur Verfügung.

      Gruß
      Roland
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Volkmar ()

    • Und hier ein etwas komplexeres Beispiel mit Sprüngen und Strings direkt aus dem XProfan-Quellcode (Verschlüsselungsroutine, basierend auf einem Assemblercode von Frank Abbing):

      Quellcode

      1. window 1000,1000
      2. declare string text, pw
      3. ASM "crypt", 2
      4. // Crypt proc
      5. PUSH EBX
      6. PUSH ESI
      7. PUSH EDI
      8. PUSH EBP
      9. // setze AnsiString-Pointer
      10. MOV EDX, Par1 // s
      11. MOV ECX, [edx-4] // len(s)
      12. MOV EBX, Par2 // pw
      13. MOV ESI, [ebx-4] // len(pw)
      14. MOV EDI,0
      15. @@jaguar:
      16. mov al,[edx]
      17. xor al,[ebx+edi]
      18. mov [edx],al
      19. inc edx
      20. inc edi
      21. cmp esi,edi
      22. jne @@kniez
      23. mov edi,0
      24. @@kniez:
      25. sub ecx,1
      26. jne @@jaguar
      27. XOR EAX, EAX
      28. POP EBP
      29. POP EDI
      30. POP ESI
      31. POP EBX
      32. ENDASM
      33. text = "Mein Text"
      34. pw = "Pass22"
      35. Var Long Ergebnis = Crypt(text, pw)
      36. Print Ergebnis
      37. Print text
      38. Crypt(text, pw)
      39. Print text
      40. WaitInput
      Alles anzeigen
      Die vier PUSH un POP am Anfnag/Ende kann man auch weglassen. Beim Delphi-Inline-Assembler sind sie empfehlenswert, da Delphi die Register auch zur Parameterübergabe nutzt. Die "@@" bei den Labels kann man auch weglassen. Ich habe den Teil eben einfach aus meinem Delphicode kopiert und lediglich "Par1" und "Par2" eingesetzt.

      Gruß
      Roland
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de
    • Und auch die Windows-API kann genutzt werden. Drei unterschiedliche Beispiele mit gleichem Ergebnis:

      Quellcode

      1. CLS
      2. Declare handle hDLL, Funk, String Text
      3. hDLL = UseDLL("USER32.DLL") ' Handle von USER32 ermitteln
      4. funk = ~GetProcAddress(hDLL, "MessageBoxA") ' Adresse der Funkton ermitteln
      5. ASM "MsgBox", 5 ' Ein Parameter Adresse + 4 Parameter für die Messagebox
      6. // Parameter einlesen
      7. MOV ECX, Par1
      8. MOV EAX, Par2
      9. MOV EDX, Par3
      10. MOV ESI, Par4
      11. MOV EBX, Par5
      12. // Messagebox-Parameter auf den Stack
      13. PUSH EBX
      14. PUSH ESI
      15. PUSH EDX
      16. PUSH EAX
      17. // Funktion aufrufen
      18. CALL ECX
      19. ENDASM
      20. Print MsgBox(funk, %hWnd, "Das ist die Botschaft!", "Titel", 51)
      21. waitinput
      Alles anzeigen
      Es geht auch mit weniger verschwenderischem Registerverbrauch:

      Quellcode

      1. $H windows.ph ' WindowsHeaderdatei nutzen
      2. CLS
      3. Declare handle hDLL, Funk, String Text
      4. hDLL = UseDLL("USER32.DLL") ' Handle von USER32 ermitteln
      5. funk = ~GetProcAddress(hDLL, "MessageBoxA") ' Adresse der Funkton ermitteln
      6. ASM "MsgBox", 5 ' Ein Parameter Adresse + 4 Parameter für die Messagebox
      7. // Parameter einlesen
      8. MOV EAX, Par5
      9. PUSH EAX
      10. MOV EAX, Par4
      11. PUSH EAX
      12. MOV EAX, Par3
      13. PUSH EAX
      14. MOV EAX, Par2
      15. PUSH EAX
      16. MOV EAX, Par1
      17. // Funktion aufrufen
      18. CALL EAX
      19. ENDASM
      20. Print Funk
      21. Print MsgBox(funk, %hWnd, "Das ist die Botschaft!", "Titel", 51)
      22. waitinput
      Alles anzeigen
      Und ein erstes Makro "FCALL" erlaubt den direkten Aufruf aller mit ImportFunc, ImportDLL und ASM importierten Funktionen:

      Quellcode

      1. $H windows.ph ' WindowsHeaderdatei nutzen
      2. CLS
      3. Declare handle hDLL, String Text
      4. hDLL = UseDLL("USER32.DLL") ' Handle von USER32 ermitteln
      5. ImportFunc(hDLL, "MessageBoxA", "")
      6. ASM "MsgBox", 4 ' 4 Parameter für die Messagebox
      7. // Parameter einlesen
      8. MOV EAX, Par4
      9. PUSH EAX
      10. MOV EAX, Par3
      11. PUSH EAX
      12. MOV EAX, Par2
      13. PUSH EAX
      14. MOV EAX, Par1
      15. PUSH EAX
      16. // Funktion aufrufen
      17. FCALL MessageBoxA
      18. ENDASM
      19. Print MsgBox(%hWnd, "Das ist die Botschaft!", "Titel", 51)
      20. waitinput
      Alles anzeigen
      Beim Assemblieren wird aus FCALL dann "MOV EAX, Funktionsadresse" und "CALL EAX", wie auch im erzeugten Listing zu sehen ist. Das EAX-Register bietet sich hier an, weil es ja ehr von der Funktion verändert wird und das Ergebnis aufnimmt.
      Ach ja: Bei der innerhalb Windows gültigen Aufrufkonvention STDCALL ist immer die Funktion für das Aufräumen des Stacks zuständig. Das heißt, die auf den Stapel geschobenen Parameter werden von der Funktion wieder von diesem entfernt. Für den Stapel gilt "Last In - First Out", daher wird der erste Parameter zuletzt auf den Stapel gelegt.

      Gruß
      Roland
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von RGH ()

    • Und hier etwas für die Mathematiker unter uns:

      Quellcode

      1. // Quelle des Assemblerlistings:
      2. // https://helloacm.com/fib-number-inline-assembly-delphi/
      3. CLS
      4. Declare int zahl
      5. ASM "Fibonacci", 1
      6. PUSH EBX
      7. MOV EAX,Par1
      8. TEST EAX, EAX
      9. JZ @M
      10. MOV ECX, EAX
      11. XOR EAX, EAX
      12. MOV EDX, 1
      13. @L:
      14. MOV EBX, EDX
      15. ADD EDX, EAX
      16. MOV EAX, EBX
      17. LOOP @L
      18. @M:
      19. POP EBX
      20. ENDASM
      21. For zahl,1,30
      22. Print Fibonacci(zahl)
      23. EndFor
      24. WaitInput
      25. End
      Alles anzeigen

      Gruß
      Roland
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de
    • Da mir an ASM-Wissen noch etliches fehlt :
      Vielleicht kann Roland oder wer anderes mir weiterhelfen.
      Ich will mir ein Spezialfunktion (Enum) bauen. Da ein
      Assembler auch ein Array als linearen Speicherbereich
      ansieht, könnte man diese Funktion sowohl für Arrays
      als auch für Bereiche nutzen.
      Das hier funktioniert noch nicht :

      Quellcode

      1. Declare Int A[20]
      2. Declare Memory Bereich
      3. Dim Bereich, 100
      4. Long Bereich,0 = 1,2,3,4,5
      5. CLS
      6. ASM "Enum", 3
      7. PUSH EBX
      8. PUSH ESI
      9. PUSH EDI
      10. PUSH EBP
      11. MOV ESI,PAR1
      12. MOV EDI,PAR2
      13. MOV EBX,PAR3
      14. XOR ECX,ECX
      15. MOV EDX,1
      16. @B:
      17. ADD ESI,4 ' offset + 4 Bytes
      18. MOV ESI,EDX
      19. MUL ESI,ECX
      20. MUL ESI,EBX
      21. INC EDX
      22. INC ECX
      23. CMP ECX,EDI
      24. JNE @B
      25. ENDASM
      26. Enum(A[], 20, 1)
      27. Enum(Bereich, 20, 1)
      28. WhileLoop 0,19
      29. Print "Array : "; A[&LOOP], "Bereich : "; Long(Bereich, &LOOP * 4)
      30. EndWhile
      31. Print
      32. WaitKey
      33. Dispose Bereich
      34. End
      Alles anzeigen
      Der zweite Parameter ist die Anzahl der Elemente (z.B. Größe des Arrays).

      Enum(A[], 20, 1) sollte ein Array forlaufend numeriert füllen,
      also
      A[0] = 1
      A[1] = 2
      A[2] = 3
      .....
      A[19] = 20
      Enum(A[], 20, 10) sollte ein Array in 10er Schritten füllen,
      also
      A[0] = 10
      A[1] = 20
      A[2] = 30
      .....
      A[19] = 200

      Wäre dann auch für Bereiche interessant.
      Long Bereich, 0 = 1,2,3,4,5
      geht ja sowieso. Aber bei z.B. Tausenden von Einträgen wäre es doch, auch mit
      einer Schleife, langsamer. Da könnte man doch schön die Schnelligkeit von ASM
      ausnutzen.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Volkmar ()

    • Könnte zum Beispiel so aussehen

      Quellcode

      1. Declare Int A[20]
      2. Declare Memory Bereich
      3. Dim Bereich, 100
      4. Long Bereich,0 = 1,2,3,4,5
      5. CLS
      6. ASM "Enum", 3
      7. PUSH EBX
      8. PUSH ECX
      9. PUSH ESI
      10. MOV ESI,PAR1 // Zieladresse
      11. MOV ECX,PAR2 // Größe
      12. MOV EBX,PAR3 // Startwert
      13. @schleife:
      14. MOV [ESI],EBX // Wert in Speicher
      15. ADD ESI, 4 // Nächste Adresse
      16. INC EBX // Nächster Wert
      17. DEC ECX // Wertzähler
      18. JNZ @schleife // Wertzahl > 0 bleibt in Schleife
      19. // gepuschte Register in umgekehrter Reihenfolge wird holen
      20. POP ESI
      21. POP ECX
      22. POP EBX
      23. ENDASM
      24. Enum(Addr(A[0]), 20, 1)
      25. Enum(Bereich, 20, 1)
      26. WhileLoop 0,19
      27. Print "Array : "; A[&LOOP], "Bereich : "; Long(Bereich, &LOOP * 4)
      28. EndWhile
      29. Print
      30. WaitKey
      31. Dispose Bereich
      32. End
      Alles anzeigen



      Gruß Volkmar
    • Geht natürlich auch mit "echter" Schleife, das ist dann noch eine Zeile kürzer

      Quellcode

      1. Declare Int A[20]
      2. Declare Memory Bereich
      3. Dim Bereich, 100
      4. Long Bereich,0 = 1,2,3,4,5
      5. CLS
      6. ASM "Enum", 3
      7. PUSH EBX
      8. PUSH ECX
      9. PUSH ESI
      10. MOV ESI,PAR1 // Zieladresse
      11. MOV ECX,PAR2 // Größe
      12. MOV EBX,PAR3 // Startwert
      13. @schleife:
      14. MOV [ESI],EBX // Wert in Speicher
      15. ADD ESI, 4 // Nächste Adresse
      16. INC EBX
      17. LOOPNZ @schleife
      18. // gepuschte Register in umgekehrter Reihenfolge wird holen
      19. POP ESI
      20. POP ECX
      21. POP EBX
      22. ENDASM
      23. Enum(Addr(A[0]), 20, 1)
      24. Enum(Bereich, 20, 1)
      25. WhileLoop 0,19
      26. Print "Array : "; A[&LOOP], "Bereich : "; Long(Bereich, &LOOP * 4)
      27. EndWhile
      28. Print
      29. WaitKey
      30. Dispose Bereich
      31. End
      Alles anzeigen



      Gruß Volkmar
    • Klappt fast so, wie ich es mir wünsche.
      Bloß mit dem 3. Parameter wollte ich es anders :
      Bei
      Enum(Addr[0], 20, 10)
      sollte nicht bei 10 angefangen werden
      -> A[0] = 10, A[1] = 11 usw.
      Es sollten eigentlich 10er Schritte werden.
      also A[0] = 10, A[1] = 20, A[2] = 30

      Also ist EBX kein Startwert, sondern ein STEP.
      Also müßte ich irgendwo noch mit EBX multiplizieren.

      Ansonsten super gemacht, auch mit den Kommentaren dahinter.
      Dann lernt man das auch schneller.
    • Dann habe ich falsch gedacht. Geht aber auch mit einer einfachen Addidition

      Quellcode

      1. Declare Int A[20]
      2. Declare Memory Bereich
      3. Dim Bereich, 100
      4. Long Bereich,0 = 1,2,3,4,5
      5. CLS
      6. ASM "Enum", 3
      7. PUSH EAX
      8. PUSH EBX
      9. PUSH ECX
      10. PUSH ESI
      11. MOV ESI,PAR1 // Zieladresse
      12. MOV ECX,PAR2 // Größe
      13. MOV EBX,PAR3 // Schritt
      14. MOV EAX, 1 // Startwert immer 1
      15. @schleife:
      16. MOV [ESI],EAX // Wert in Speicher
      17. ADD ESI, 4 // Nächste Adresse
      18. ADD EAX, EBX
      19. LOOPNZ @schleife
      20. // gepuschte Register in umgekehrter Reihenfolge wird holen
      21. POP ESI
      22. POP ECX
      23. POP EBX
      24. POP EAX
      25. ENDASM
      26. Enum(Addr(A[0]), 20, 7)
      27. Enum(Bereich, 20, 7)
      28. WhileLoop 0,19
      29. Print "Array : "; A[&LOOP], "Bereich : "; Long(Bereich, &LOOP * 4)
      30. EndWhile
      31. Print
      32. WaitKey
      33. Dispose Bereich
      34. End
      Alles anzeigen



      Gruß Volkmar
    • Noch nicht ganz.
      Hier haste bei A[0] = 1 und bei A[1] = 11
      und nicht, wie gewollt bei A[0] = 10 und A[1] = 20

      Das ganze soll ja so funktionieren, daß beim 3.Parameter
      bei Enum(A[0], 20, 1) ganz normal aufnummeriert wird
      und halt eben bei > 1 * Para3

      So sieht es mit XProfan aus :

      Quellcode

      1. Declare Int A[20], B[20]
      2. Enum(A[], 20, 1)
      3. Enum(B[], 20, 10)
      4. WhileLoop 0, 19
      5. Print "Array 1 : "; A[&LOOP], " Array 2 : "; B[&Loop]
      6. EndWhile
      7. Waitkey
      8. Proc Enum
      9. Parameters Int Z[], Anzahl, Step
      10. WhileLoop 1, Anzahl
      11. Z[&LOOP - 1] = &LOOP * Step
      12. EndWhile
      13. EndProc
      14. End
      Alles anzeigen
    • Für alle, die noch gerne mit den älteren Versionen bzw.
      Interpreter arbeiten :
      Dank Rolands .lst - Datei, die bei der ASM-Funktion anfällt,
      kann man sehr schön auch für ältere Profanversionen den
      Bytecode-String in einen Bereich schreiben.

      Quellcode

      1. Declare Int A[20], Memory Bereich
      2. Dim Bereich, 100
      3. Cls
      4. EnumArray(A[], 20, 10)
      5. EnumBereich(Bereich, 20, 1)
      6. WhileLoop 0, 19
      7. Print "Array : "; A[&LOOP], " Bereich : "; Long(Bereich, &LOOP * 4)
      8. EndWhile
      9. Waitkey
      10. Proc EnumArray
      11. Parameters Int Z[], Anzahl, Step
      12. Declare Memory ASMBereich, Int anz, String b
      13. b = "55,89,E5,50,53,51,56,8B,75,08,8B,4D,0C,8B,5D,10,89,D8,89,06,81,C6,04,00,00,00,\
      14. 01,D8,E0,F4,5E,59,5B,58,89,EC,5D,C2,0C,00,"
      15. anz = Len(b, ",")
      16. Dim ASMBereich, anz
      17. Byte ASMBereich, 0 = $55,$89,$E5,$50,$53,$51,$56,$8B,$75,$08,$8B,$4D,$0C,$8B,$5D,$10,$89,$D8,$89,$06,$81,$C6,$04,$00,$00,$00,\
      18. $01,$D8,$E0,$F4,$5E,$59,$5B,$58,$89,$EC,$5D,$C2,$0C,$00
      19. CALL(ASMBereich, Addr(Z[0]), Anzahl, Step)
      20. Dispose ASMBereich
      21. EndProc
      22. Proc EnumBereich
      23. Parameters Memory Z, Anzahl, Step
      24. Declare Memory ASMBereich, Int anz, String b
      25. b = "55,89,E5,50,53,51,56,8B,75,08,8B,4D,0C,8B,5D,10,89,D8,89,06,81,C6,04,00,00,00,\
      26. 01,D8,E0,F4,5E,59,5B,58,89,EC,5D,C2,0C,00,"
      27. anz = Len(b, ",")
      28. Dim ASMBereich, anz
      29. Byte ASMBereich, 0 = $55,$89,$E5,$50,$53,$51,$56,$8B,$75,$08,$8B,$4D,$0C,$8B,$5D,$10,$89,$D8,$89,$06,$81,$C6,$04,$00,$00,$00,\
      30. $01,$D8,$E0,$F4,$5E,$59,$5B,$58,$89,$EC,$5D,$C2,$0C,$00
      31. CALL(ASMBereich, Z, Anzahl, Step)
      32. Dispose ASMBereich
      33. EndProc
      34. Dispose Bereich
      35. End
      Alles anzeigen
      So haben dann alle was davon.
      Da war zwar etwas Handarbeit angesagt, aber so groß werden die Asmlistings ja auch nicht.
      Verbesserungen an obigem Code sind erwünscht. Vielleicht sollte man auch ein Tool dazu
      schreiben, das die Handarbeit erledigt.
    • So in etwa? Der Code wird in die Zwischenablage gestellt und kann dann in den Quelltext reinkopiert werden. Das Dispose von ASMBereich muß dann selbst an passender Stelle eingefügt werden, wenn die Funktion nicht mehr gebraucht wird. Dateiname und Pfad zur LST-Datei in der ersten Zeile entsprechend anpassen (oder Dateidialog einbauen ;-) ) Wenn mehrere ASM-Codes im gleichen Programm verwendet werden, dann noch die Namen der Bereiche nach dem Einfügen manuell ändern!

      Quellcode

      1. Var String Eingabe = "C:\\XProfanX4alpha\\Enum.LST"
      2. Declare String Zeile
      3. Declare Int Anzahl, Teil, TeilPos
      4. Declare String Ausgabe
      5. CLS
      6. Assign #1, Eingabe
      7. Reset #1
      8. Case %IOResult : Fehler "Öffnen"
      9. WhileNot EOF(#1)
      10. Input #1, Zeile
      11. Case %IOResult : "Lesen"
      12. EndWhile
      13. Close #1
      14. Teil = Len(Zeile)
      15. TeilPos = 0
      16. While TeilPos < Teil
      17. Ausgabe = Ausgabe + Mid$(Zeile, TeilPos + 1, 2) + ","
      18. Inc TeilPos, 2
      19. Inc Anzahl
      20. If Anzahl = 16
      21. Ausgabe = Ausgabe + "\\\n"
      22. Anzahl = 0
      23. EndIf
      24. EndWhile
      25. Ausgabe = Del$(Ausgabe, Len(Ausgabe), 1)
      26. Ausgabe = "Declare Mem ASMBereich\nDIM ASMBereich, " + Str$(Teil \ 2) + "\nByte ASMBereich, 0 = " + Ausgabe
      27. ClearClip
      28. PutClip Ausgabe
      29. Print Ausgabe
      30. Print
      31. Print "wurde in die Zwischenablage kopiert"
      32. WaitInput
      33. End
      34. Proc Fehler
      35. Parameters String Meldung
      36. Meldung = "Fehler beim " + Meldung + " von " + Eingabe + "\nProgramm wird abgebrochen"
      37. MessageBox(Meldung, "Fehler", 16)
      38. End
      39. EndProc
      Alles anzeigen
      Das Ergebnis sollte dann so aussehen

      Quelltext schrieb:

      Declare Mem ASMBereich
      DIM ASMBereich, 40
      Byte ASMBereich, 0 = 55,89,E5,50,53,51,56,8B,75,08,8B,4D,0C,8B,5D,10,\
      89,D8,89,06,81,C6,04,00,00,00,01,D8,E0,F4,5E,59,\
      5B,58,89,EC,5D,C2,0C,00
      Code nicht verwenden, da fehlen die $ vor den Hex-Werten. Korrigierte Fassung in #16

      . Dank für den Hinweis an H.Brill.


      Gruß Volkmar

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von Volkmar ()

    • Man muß nur aufpassen :
      z.B. das E5 oder 8B ging bei mir als Bytezuweisung nicht.
      Deshalb hatte ich bei jedem Byte ein $ davor gesetzt.

      Was noch besser wäre :
      Da Roland ja sowieso den Bytecodestring in der .lst
      zusammensetzt, wäre es ja für ihn kein Problem bzw.
      keine größere Arbeit, gleich ein $ vor jedes Byte und ein
      Komma hinter jedes Byte zu setzen. Mit einem Set-Befehl
      oder Compilerschalter könnte man evtl. auch bestimmen,
      wie man es mag : Klassisch, wie bisher oder spezifisch, wie
      oben geschrieben.
      Wenn er dann noch die Anzahl der Bytes in .lst schreibt,
      kann man den Bereich auch gleich darauf dim'en, ohne
      mit Len() zu zählen.

      Ist ja nur gedacht, frühere Profanversionen zu bedienen
      bzw. Könnte man sich auch Resourcen von Bytefolgen anlegen,
      die bei Start des Interpreters / Programms geladen werden.
      Ich denke, sowas wäre mit einer STRINGTABLE und RCDATA
      leicht machbar.
    • Hast Du natürlich Recht, da habe ich wieder mal gepennt. Das $ muß schon vor jedem Wert stehen, sind ja grundsätzlich HEX-Werte.

      Quellcode

      1. Var String Eingabe = "C:\\XProfanX4alpha\\Enum.LST"
      2. Declare String Zeile
      3. Declare Int Anzahl, Teil, TeilPos
      4. Declare String Ausgabe
      5. CLS
      6. Assign #1, Eingabe
      7. Reset #1
      8. Case %IOResult : Fehler "Öffnen"
      9. WhileNot EOF(#1)
      10. Input #1, Zeile
      11. Case %IOResult : "Lesen"
      12. EndWhile
      13. Close #1
      14. Teil = Len(Zeile)
      15. TeilPos = 0
      16. While TeilPos < Teil
      17. Ausgabe = Ausgabe + "$" + Mid$(Zeile, TeilPos + 1, 2) + ","
      18. Inc TeilPos, 2
      19. Inc Anzahl
      20. If Anzahl = 16
      21. Ausgabe = Ausgabe + "\\\n"
      22. Anzahl = 0
      23. EndIf
      24. EndWhile
      25. Ausgabe = Del$(Ausgabe, Len(Ausgabe), 1)
      26. Ausgabe = "Declare Mem ASMBereich\nDIM ASMBereich, " + Str$(Teil \ 2) + "\nByte ASMBereich, 0 = " + Ausgabe
      27. ClearClip
      28. PutClip Ausgabe
      29. Print Ausgabe
      30. Print
      31. Print "wurde in die Zwischenablage kopiert"
      32. WaitInput
      33. End
      34. Proc Fehler
      35. Parameters String Meldung
      36. Meldung = "Fehler beim " + Meldung + " von " + Eingabe + "\nProgramm wird abgebrochen"
      37. MessageBox(Meldung, "Fehler", 16)
      38. End
      39. EndProc
      Alles anzeigen


      Gruß Volkmar
    • Warten wir mal ab, was an ASM-Codes zusammenkommt.

      Als Zwischenlösung, wenn man halt eine .exe haben will
      oder eben für frühere Versionen ist es interessant.

      Ansonsten kann man mit deiner Lösung im Augenblick
      auch gut leben.

      Also ran an die Vollspeed-Lösungen für XPROFAN !!!!!!!! :top:

      PS:
      Eine ASM-Routine als Ersatz für Translate$ steht bei mir
      als nächstes auf dem Plan. Die ist nämlich bei großen
      Datenmengen auch recht langsam.
      Aber da warte ich noch was, in der Hoffnung, daß Roland
      noch ein paar ASM-Stringroutinen (MOVXX o.ä.)
      implementiert.

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von H.Brill ()

    • Als etwas größeres Beispiel mit Strings: die abgwandelte MsgBox:

      Quellcode

      1. $H windows.ph ' WindowsHeaderdatei nutzen
      2. CLS
      3. Declare handle hDLL, String Text
      4. hDLL = UseDLL("USER32.DLL") ' Handle von USER32 ermitteln
      5. ImportFunc(hDLL, "MessageBoxA", "")
      6. ASM "MsgBox", 1 ' Ein Parameter Adresse + 4 Parameter für die Messagebox
      7. JMP Start
      8. Typ:
      9. DD 51
      10. Titel:
      11. DS "Titel Total!\z"
      12. Text:
      13. DS "Das ist auch ein Hinweis!\z"
      14. Start:
      15. // Parameter einlesen
      16. MOV EAX, [Typ]
      17. PUSH EAX
      18. MOV EAX, Titel
      19. PUSH EAX
      20. MOV EAX, Text
      21. PUSH EAX
      22. MOV EAX, Par1
      23. PUSH EAX
      24. // Funktion aufrufen
      25. FCALL MessageBoxA
      26. ENDASM
      27. Print MsgBox(%hWnd)
      28. waitinput
      Alles anzeigen

      Man beachte:
      Bei Typ steht der Wert an der durch das Label "Typ:" angegebenen Adresse. Die Funktion erwartet den direkten Wert, deshalb wird hier der Wert, der an dieser Adresse steht nach EAX geholt: Das Label steht in eckigen Klammern.
      Bei den Texten, steht der Text jeweils an der durch das Label angegebenen Adresse. Da die Funktion hier die Adressen der Strings erwartet, werden diese direkt nach EAX kopiert, also steht das Label hier ohne eckige Klammern.

      Ach ja: Die Strings sollten natürlich mit einem Null-Byte ("\z") aufhören, sonst wird es seltsam. Und für den Typ wird ein DD-Speicherplatz (4 Byte = 32 Bit) benötigt, da MOVE EAX, [Label] einen 32-Bit-Wert von der angegebenen Adresse holt. (Bei z.B. MOV AL,[Label] hätte auch DB für ein Byte genügt.)

      Gruß
      Roland
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von RGH ()

    • Und das an sich unsinnige Beispiel zeigt, dass man die Werte an den mit Dx reservierten Speicherstellen auch verändern kann:

      Quellcode

      1. $H windows.ph ' WindowsHeaderdatei nutzen
      2. CLS
      3. Declare handle hDLL, String Text
      4. hDLL = UseDLL("USER32.DLL") ' Handle von USER32 ermitteln
      5. ImportFunc(hDLL, "MessageBoxA", "")
      6. ASM "MsgBox", 1
      7. JMP Start
      8. Typ:
      9. DD 51
      10. Titel:
      11. DS "Titel Total!\z"
      12. Text:
      13. DS "Das ist auch ein Hinweis!\z"
      14. Start:
      15. // Wert an Adresse TYP verändern
      16. MOV EBX, 18
      17. MOV [Typ],EBX
      18. // Parameter einlesen
      19. MOV EAX, [Typ]
      20. PUSH EAX
      21. MOV EAX, Titel
      22. PUSH EAX
      23. MOV EAX, Text
      24. PUSH EAX
      25. MOV EAX, Par1
      26. PUSH EAX
      27. // Funktion aufrufen
      28. FCALL MessageBoxA
      29. ENDASM
      30. Print MsgBox(%hWnd)
      31. waitinput
      Alles anzeigen
      Intel Duo E8400 3,0 GHz / 4 GB RAM / 1000 GB HDD / ATI Radeon HD4770 512 MB / Windows 7(32) - XProfan X3
      AMD Athlon II X2 2,9 GHz / 3 GB RAM / 500 GB HDD / ATI Radeon 3000 (onboard) / Windows 10(64) - XProfan X3


      http://www.xprofan.de