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

    • p. specht schrieb:

      Bitte wie komme ich an die Call-Adresse des mit ASM erzeugten Maschinencodes?
      ProcAddr liefert derzeit Fehlermeldung ...
      Zur Zeit überhaupt nicht. ProcAddr funktioniert nur für XProfan-Prozeduren und weist diesen eine feste Adresse zu. Mit ASM-ENDASM werden die Funktionen genau so in die interne Liste externer Funktionen eingetragen, wie mit ImportFunc oder ImportDLL. Da die Funktionen ja über ihren Namen aufgerufen werden (auch in ASM-Funktionen mit FCALL), benötigt man (normalerweise) ihre Adressen nicht.

      Ich habe aber geplant, bei ASM-ENDASM zwei Systemvariablen zu füllen, die Startadresse und Länge des erzeugten Codes bereitstellen, auch wenn ich nicht so recht weiß, was man damit Sinnvolles anfangen kann.

      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
    • ad 39: Ich habe beobachtet, daß "Vorwärtsverkettete Indexlisten" im Grundzustand (also vor dem mitsortiert werden nach der neuen Ordnung) immer auf das NÄCHSTE Element der aktuellen Ordnung weisen sollten, nicht auf sich selbst. Auch dazu wäre es super, den Basiswert der Zählung bei 1 anzusetzen, da ja das nächste anzuspringende Element der Indexordnung dann das mit dem Index 1 ist...(Ich weiß aber nicht, ob Heinz das überhaupt im Auge hatte. Es wäre jedenfalls ein weiteres Argument für Element[0]="1" ).

      ad 37: Die Call-Addy könnte sinnvoll sein, wenn mehrere ASM-ENDASM-Module zusammenarbeiten sollen. Auch Callback-Techniken benötigen das ja ... (wobei ich keine Ahnung von Callback habe). An selbstmodifizierenden Code denke ich natürlich nicht, - das wäre ja gegen alles, was den Informatik-Göttern heilig ist ...
      Gruss

      P.S: Mir gefällt sehr, daß man tatsächlich "in Line" codieren kann. Das klappt sonst in keinem der bekannten Assembler:

      Quellcode

      1. WindowTitle "Halber Sinn des Lebens":CLS:ASM "zwei",0:jmp hopp:zw:
      2. dd 42:hopp:
      3. LEA eax,[zw]:ENDASM:ASM "halb",1:mov eax,par1:mov eax,[eax]:shr eax:ENDASM
      4. Print halb(zwei()):waitinput

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von p. specht ()

    • Besser langsam, aber dafür sorgfältig angehen...

      Die untenstehend von RGH bekanntgegebenben Neuerungen wurden in das "vorläufige Merkblatt_XASM.pdf" eingearbeitet. Die alte Download-Addy dazu ist nicht mehr gültig.

      Dafür gibt es ergänzend ein Merkblatt zu Bedingungen und Schleifen in Assembler.

      Und hier ein Testcode, der sich selbst byteweise ausgibt und dann auch im Clipboard zu finden ist.
      Gruss

      Quellcode

      1. WindowTitle "Selbsterforschung"
      2. WindowStyle 24:Window 0,0-%maxx,%maxy:showmax
      3. set("AsmMode",2):font 2
      4. ASM "Test2",1:data:
      5. mov ebx,par1:mov ecx,data:add ecx,ebx:xor eax,eax:mov al,[ecx]:exyt:
      6. ENDASM
      7. whileloop -3,-1
      8. print right$("0"+hex$(test2(&Loop)),2); '55 89 E5 = Pgm-Start
      9. endwhile
      10. print
      11. whileloop 14,19
      12. print right$("0"+hex$(test2(&Loop)),2); '89 EC 5D C2 (= Pgm-Ende)+ 04 00 (= 0004/4 = 1 Parameter)
      13. endwhile
      14. print
      15. clearclip
      16. whileloop -3,19
      17. print right$("0"+hex$(test2(&Loop)),2); 'Programm
      18. putclip right$("0"+hex$(test2(&Loop)),2)
      19. endwhile
      20. print:print "\n ASM-PGM Hex-Bytecode im Clipboard"
      21. Waitinput 15000
      Alles anzeigen
      P.S.: Vielleicht wäre eine separate Rubrik für solche und andere User-Codestücke sinnvoll.
      Dann könnte dieser Thread allein für Neuerungen reserviert bleiben...

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von p. specht ()

    • Habe hier auch was, das 2 Strings zusammensetzen soll.
      Das hatte ich aus dem Netz auch so übernommen.
      Irgendwie mache ich da was falsch, was das Schreiben
      an bestimmte Adressen angeht.
      Hier kommt eine Fehlermeldung :

      Quellcode

      1. Declare String s1, s2
      2. s1 = "Hallo \z"
      3. s2 = "Welt\z"
      4. Cls
      5. ASM "api_strcat", 2
      6. MOV ESI, Par1
      7. MOV EDI, Par2
      8. CALL strcat
      9. strcat:
      10. XOR ECX,ECX
      11. MOV EBP,ESI
      12. lp1:
      13. LODSB
      14. OR AL,AL
      15. JZ lp1d
      16. INC ECX
      17. JMP lp1
      18. lp1d:
      19. MOV ESI,EDI
      20. MOV EBX,ECX
      21. lp2:
      22. LODSB
      23. OR AL,AL
      24. JZ lp2d
      25. MOV [EBP+EBX],AL
      26. INC EBX
      27. JMP lp2
      28. XOR AL,AL
      29. MOV [EBP+EBX],AL
      30. lp2d:
      31. ENDASM
      32. Print api_strcat(s1, s2)
      33. WaitKey
      34. End
      Alles anzeigen
      Da habe ich den Bogen noch nicht so raus.
      PS : Zuerst mußte ich alle TABs entfernen. Die mag der Inline Assembler irgendwie nicht,
      bzw. gibt mir schon in der ersten Zeile einen Fehler, wo er den Befehl nicht kennt.
    • Erst mal kann das Ergebnis so nicht funktionieren. Die Assemblerroutine gibt einen Wert in EAX zurück, das ist ein 32-Bit-Wert, also eine Zahl, kein String. Prinzipiell könnte man zwar mit ausreichenden Kenntnissen Speicher reservieren und in EAX das Handle zurückgeben... das stellt Bedingungen an den nachfolgenden Programmteil. Also lieber nicht.
      Sieh Assemblerroutinen so an, wie API-Aufrufe. Es kommt immer eine Zahl zurück. Strings kommen in einem Speicherbereich, den Du ausreichend dimensioniert als Parameter übergibst. Zudem kommt mir das Ganze irgendwie aus dem Zusammenhang gerissen vor, da taucht ein CALL in die eigene Routine auf, und es gibt kein passendes RET. CALL und RET gehören zusammen wie PUSH und POP, da immer Werte auf den Stack gelegt und wieder abgeholt werden.
      Und spiele nicht mit dem Base-Pointer, den stellt Roland schon so ein, wie er gebraucht wird.

      Gruß Volkmar
    • So, habe nun auch eine Version fertig. StrCat könnte man etwa so machen

      Quellcode

      1. Declare String s1, s2
      2. s1 = "Hall0 \z"
      3. s2 = "Welt\z"
      4. s1 = s1 + Space$(Len(s2)) ' String verlängern, um Ziel aufzunehmen
      5. Cls
      6. ASM "api_strcat", 2
      7. MOV ESI, Par1
      8. MOV EDI, Par2
      9. CLD // directionflag setzen, man weiß ja nie, wie es gerade steht :-)
      10. lp1:
      11. LODSB
      12. OR AL,AL
      13. JNZ lp1
      14. lp1d:
      15. DEC ESI
      16. XCHG ESI, EDI
      17. // Quelle und Ziel tauschen, da wir jetzt in Par1 schreiben wollen
      18. lp2:
      19. LODSB
      20. STOSB
      21. OR AL,AL
      22. JZ lp2d
      23. JMP lp2
      24. XOR AL,AL
      25. MOVSB
      26. lp2d:
      27. ENDASM
      28. Print api_strcat(s1, s2)
      29. Print Trim$(s1)+ "!!"
      30. WaitKey
      31. End
      Alles anzeigen

      Und in fremde Codes gucken ist doch gar nicht so verkehrt. Nur aus dem Zusammenhang gerissen ist da Einiges anzupassen. Im Original hat das sicher funktioniert. Aber dort mußte auch niemand auf den "Funktionsrahmen" und die Bedingungen in Profan Rücksicht nehmen. Ist also immer mit etwas Anpassung zu verwenden. Mit etwas Übung wird das schon. Ich muß jetzt auch viel nachdenken, es ist etliche Jahre her, als ich den letzten Assemblercode zusammengklopft habe ;-)
      Die Zahl, die bei Print ausgegeben wird, sagt garnichts aus, das ist der aktuelle EAX-Inhalt. Und das Trim$() bei der Ergebnisanzeige kann hier auch entfallen, da die Stringlänge vorher berechnet wurde.

      Gruß Volkmar

      PS: Code nochmal geändert, da wurde ein zusätzliches Leerzeichen eingebaut, weil das Schlußzeichen (Byte 0) als gültige Zeichenposition mitgezählt wurde, nach der dann der zweite String eingefügt wird :oops:

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

    • Und Speicher belegen und freigeben könnte man in etwa so machen.

      Allerdings bekomme ich es nicht mal zum kompilieren.

      Trotzdem... TEST, TEST, TEST

      Quellcode

      1. '$I Mem_ASM.INC
      2. '$H C:\XProfan\Include\Windows.ph
      3. '$IFNDEF MEM_ASM
      4. '$DEFINE MEM_ASM
      5. Declare Handle mwmem_hDLL
      6. mwmem_hDLL = UseDLL("KERNEL32.DLL")
      7. ImportFunc( mwmem_hDLL, "GetLastError", "sys_GetLastError" ) // GetLastError( )
      8. ImportFunc( mwmem_hDLL, "GlobalAlloc", "sys_GlobalAlloc" ) // GlobalAlloc( flags, Size )
      9. ImportFunc( mwmem_hDLL, "GlobalFree", "sys_GlobalFree" ) // GlobalFree( hMem )
      10. ImportFunc( mwmem_hDLL, "GlobalHandle", "sys_GlobalHandle" ) // GlobalHandle( pMem )
      11. ImportFunc( mwmem_hDLL, "GlobalLock", "sys_GlobalLock" ) // GlobalLock( hMem )
      12. ImportFunc( mwmem_hDLL, "GlobalReAlloc", "sys_GlobalReAlloc" ) // GlobalReAlloc( hMem, Size, flags )
      13. ImportFunc( mwmem_hDLL, "GlobalSize", "sys_GlobalSize" ) // GlobalSize( hMem )
      14. ImportFunc( mwmem_hDLL, "GlobalUnlock", "sys_GlobalUnlock" ) // GlobalUnlock( hMem )
      15. ImportFunc( mwmem_hDLL, "RtlFillMemory", "sys_FillMemory" ) // FillMemory( pDest, Len, Char )
      16. ImportFunc( mwmem_hDLL, "RtlMoveMemory", "sys_MoveMemory" ) // MoveMemory( pDest, pSrc, Len ) 'Überlappung erlaubt
      17. ImportFunc( mwmem_hDLL, "RtlZeroMemory", "sys_ZeroMemory" ) // ZeroMemory( pDest, Len )
      18. // EAX, ECX, EDX müssen selbst gerettet werden (da der Windows-Standard diese zu Freiwild erklärt)
      19. /*
      20. Inhalt:
      21. Mem_New - pMem = Mem_New( Size ) - Speicher belegen/reservieren
      22. Mem_Free - bool = Mem_Free( pMem ) - Speicher freigeben
      23. Mem_Size - Size = Mem_Size( pMem ) - Größe des belegten Speichers ermitteln
      24. Mem_Clear - Size = Mem_Clear( pMem ) - Speicher mit Nullen überschreiben
      25. Mem_Fill - bool = Mem_Fill( pMem, Anz, Fill ) - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
      26. Mem_Move - bool = Mem_Move( Ziel, Quelle, Anz ) - Speicherinhalte kopieren
      27. Mem_Resize - pMem = Mem_Resize( pMem, Size ) - Speichergröße ändern/redimensionieren
      28. */
      29. ' ********************
      30. ' Mem_New() - Speicher belegen/reservieren
      31. ' pMem& = Mem_New( Size& )
      32. ' Speicher belegen
      33. ' Reserviert "Size" Bytes Speicherplatz und liefert den Speicherzeiger als Rückgabewert.
      34. ASM "Mem_New", 1
      35. PUSH ECX
      36. MOV ECX, 66 // GMEM_MOVEABLE = 2 | GMEM_ZEROINIT = 64 | GMEM_PTR = 66
      37. MOV EAX, PAR1 // Size
      38. CMP EAX, EAX // Null ?
      39. JZ @@New_Done
      40. PUSH EAX // Size
      41. PUSH ECX // Flags
      42. FCALL "sys_GlobalAlloc"
      43. CMP EAX, EAX // Null ?
      44. JZ @@New_Done
      45. PUSH EAX // hMem
      46. FCALL "sys_GlobalLock"
      47. @@New_Done:
      48. POP ECX
      49. ENDASM
      50. ' ********************
      51. ' Mem_Free() - Speicher freigeben
      52. ' bool% = Mem_Free( pMem& )
      53. ' Speicher freigeben
      54. ' Gibt den Speicherbereich auf den der Speicherzeiger zeigt wieder frei.
      55. ASM "Mem_Free", 1
      56. PUSH ECX
      57. MOV EAX, PAR1 // pMem
      58. CMP EAX, EAX
      59. JZ @@Free_Done
      60. PUSH EAX // pMem
      61. FCALL "sys_GlobalHandle"
      62. CMP EAX, EAX
      63. JZ @@Free_Error
      64. MOV ECX, EAX
      65. PUSH ECX // hMem
      66. FCALL "sys_GlobalUnlock"
      67. CMP EAX, EAX
      68. JZ @@Free_Error
      69. PUSH ECX // hMem
      70. FCALL "sys_GlobalFree"
      71. CMP EAX, EAX
      72. JNZ @@Free_Done
      73. @@Free_Error:
      74. FCALL "sys_GetLastError"
      75. @@Free_Done:
      76. POP ECX
      77. ENDASM
      78. ' ********************
      79. ' Mem_Size() - Größe des belegten Speichers ermitteln
      80. ' Size& = Mem_Size( pMem& )
      81. ' Ermittelt die Speichergröße auf die der Speicherzeiger zeigt.
      82. ' Liefert die Größe des Bereiches zurück.
      83. ASM "Mem_Size", 1
      84. PUSH ESI
      85. PUSH EDI
      86. XOR EDI,EDI
      87. MOV ESI, PAR1 // pMem
      88. CMP ESI, ESI
      89. JZ @@Size_Done
      90. PUSH ESI // pMem
      91. FCALL "sys_GlobalHandle" // --> hMem
      92. MOV ESI, EAX // hMem
      93. CMP EAX, EAX
      94. JZ @@Size_Error
      95. PUSH ESI // hMem
      96. FCALL "sys_GlobalSize" // size
      97. MOV EDI, EAX // size
      98. JNZ @@Size_Done
      99. @@Size_Error:
      100. FCALL "sys_GetLastError"
      101. @@Size_Done:
      102. MOV EAX,EDI
      103. POP EDI
      104. POP ESI
      105. ENDASM
      106. ' ********************
      107. ' Mem_Clear() - Speicher mit Nullen überschreiben
      108. ' Size& = Mem_Clear( pMem& )
      109. ' Speicher mit Nullen beschreiben
      110. ' Der angegebene (gesamte) Speicherbereich wird mit binären Nullen überschrieben.
      111. ' Für eine Teilfüllung ist Mem_Fill() zu nutzen.
      112. ' benötigt Mem_Size(), "ZeroMemory"
      113. ' Ergebnis: Größe des überschriebenen Bereiches
      114. ASM "Mem_Clear", 1
      115. PUSH ESI
      116. XOR EAX, EAX
      117. MOV ESI, PAR1 // pMem
      118. CMP ESI, ESI
      119. JZ @@Clear_Done
      120. PUSH ESI // pMem
      121. FCALL "Mem_Size"
      122. CMP EAX, EAX // size
      123. JZ @@Clear_Done
      124. PUSH EAX // size
      125. PUSH ESI // pMem
      126. FCALL "sys_ZeroMemory"
      127. @@Clear_Done:
      128. POP ESI
      129. ENDASM
      130. ' ********************
      131. ' Mem_Fill() - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
      132. ' bool% = Mem_Fill( pMem&, Anzahl&, FüllChars$ )
      133. ' belegten Speicher füllen
      134. ' Ist Anzahl = 0 dann wird Anzahl auf Mem_Size(pMem) gesetzt.
      135. ' Der angegebene Speicherbereich wird mit Füllzeichen aufgefüllt.
      136. ' - ohne diese Angabe wird mit Chr$(0) aufgefüllt
      137. ' - bei einem Zeichen wird sys_FillMemory() genutzt
      138. ' - bei mehreren Zeichen wird sys_MoveMemory() genutzt
      139. ASM "Mem_Fill", 3
      140. PUSH ESI
      141. PUSH EDI
      142. PUSH ECX
      143. PUSH EBX
      144. PUSH EDX
      145. MOV ESI, PAR3 // FillChars
      146. MOV ECX, PAR2 // Anzahl
      147. MOV EDI, PAR1 // pMem
      148. MOV EBX, [ESI - 4] // Len(FillChars)
      149. PUSH EDI // pMem
      150. FCALL "Mem_Size"
      151. CMP ECX, EAX // Anzahl <= Size ?
      152. JBE @@Fill_Anz_Inside
      153. MOV ECX, EAX // neue Anzahl
      154. @@Fill_Anz_Inside:
      155. CMP ECX, ECX // Anzahl = 0 ?
      156. JZ @@Fill_Done
      157. CMP EBX, 1 // FillChars = Null or 1 ? (nein, dann Hauptstück)
      158. JA @@Fill_more
      159. // 1 Zeichen
      160. XOR EDX, EDX // Vorgabe ist Chr$(0)
      161. CMP ESI, ESI // FillChars = NullString ?
      162. JZ @@Fill_Start
      163. MOV DL, [ESI] // Nein, dann FillChar holen
      164. @@Fill_Start:
      165. // Bereich mit einem Zeichen füllen
      166. PUSH EDX // char
      167. PUSH ECX // Anzahl
      168. PUSH EDI // pMem
      169. FCALL "sys_FillMemory"
      170. JMP @@Fill_Done
      171. // --------------------
      172. @@Fill_more:
      173. CMP EBX, ECX // LEN( FillChars ) >= Anzahl ?
      174. JAE @@Fill_MoveOne
      175. // Da wir den Füllstring mehrmals schreiben wird die Länge benötigt
      176. PUSH EBX // Len(FillChars)
      177. // ----------
      178. @@Fill_Loop:
      179. CMP ECX, EBX // Anzahl < Len(FillChars)
      180. JAE @@Fill_Hop // Nein, weiter (sonst den Rest)
      181. POP EBX // Len(FillChars)
      182. MOV EBX,ECX // überschreibe mit Rest
      183. PUSH EBX // Rest
      184. @@Fill_Hop:
      185. PUSH EBX // Len(FillChars) (oder Rest)
      186. PUSH ESI // FillChars
      187. PUSH EDI // pMem
      188. FCALL "sys_MoveMemory"
      189. POP EBX // Len(FillChars)
      190. PUSH EBX // Len(FillChars)
      191. ADD EDI, EBX // pMem + Len(FillChars)
      192. SUB ECX, EBX // Anzahl - Len(FillChars)
      193. CMP ECX, ECX // Anzahl > 0
      194. JA @@Fill_Loop
      195. // --------------------
      196. // gesicherten Wert wieder entfernen
      197. POP EBX // Len(FillChars)
      198. JMP @@Fill_Done
      199. @@Fill_MoveOne:
      200. // Es sind mehr Füllzeichen als der Bereich groß ist.
      201. // Das läßt sich in einem Rutsch erledigen.
      202. PUSH ECX // Anzahl
      203. PUSH ESI // FillChars
      204. PUSH EDI // pMem
      205. FCALL "sys_MoveMemory"
      206. @@Fill_Done:
      207. POP EDX
      208. POP EBX
      209. POP ECX
      210. POP EDI
      211. POP ESI
      212. ENDASM
      213. ' ********************
      214. ' Mem_Move() - Speicherinhalte kopieren
      215. ' bool = Mem_Move( Ziel&, Quelle&, Anzahl& )
      216. ' Der angegebene Quellbereich wird in den Zielbereich kopiert.
      217. ' (Überlappungen von Quelle und Ziel sind hier erlaubt)
      218. ASM "Mem_Move", 3
      219. PUSH ESI
      220. PUSH EDI
      221. PUSH ECX
      222. //
      223. XOR EAX, EAX // 0 = es wurde nichts kopiert
      224. MOV ECX, PAR3 // Anzahl
      225. MOV ESI, PAR2 // pQuelle
      226. MOV EDI, PAR1 // pZiel
      227. //
      228. CMP ESI, ESI // Anzahl = 0 ?
      229. JZ @@Move_Done
      230. CMP ESI, ESI // Quelle = Null
      231. JZ @@Move_Done
      232. CMP EDI, EDI // Ziel = Null
      233. JZ @@Move_Done
      234. PUSH ECX // Anzahl
      235. PUSH ESI // pQuelle
      236. PUSH EDI // pZiel
      237. FCALL "sys_MoveMemory"
      238. @@Move_Ok:
      239. INC EAX // 1 = Kopieren wurde durchgeführt
      240. @@Move_Done:
      241. POP ECX
      242. POP EDI
      243. POP ESI
      244. ENDASM
      245. ' ********************
      246. ' Mem_Resize() - Speichergröße ändern/redimensionieren
      247. ' pMem& = Mem_Resize( pMem&, Size& )
      248. ' Speicher redimensionieren
      249. ' Ändert die Speichergröße auf die der Speicherzeiger zeigt.
      250. ' Die Größe des angegebenen Speicherbereiches wird auf die neue Größe geändert (wenn ungleich).
      251. ' Bei einer Vergrößerung des Bereiches bleiben alle Daten erhalten,
      252. ' bei einer Verkleinerung nur der vordere Teil. (!!!ohne Gewähr!!!)
      253. ' Liefert den neuen Speicherzeiger zurück.
      254. ASM "Mem_Resize", 2
      255. PUSH ECX
      256. PUSH ESI
      257. PUSH EDI
      258. MOV EDI, PAR2 // Size
      259. MOV ESI, PAR1 // pMem
      260. CMP ESI, ESI // Nullzeiger ? Dann Mem_New(Size)
      261. JZ @@Resize_New
      262. PUSH ESI // pMem
      263. FCALL "sys_GlobalHandle" // --> hMem
      264. CMP ESI, ESI
      265. JZ @@Resize_Error
      266. MOV ESI, EAX // hMem
      267. PUSH ESI // hMem
      268. FCALL "sys_GlobalSize" // OldSize
      269. CMP EAX, EAX // Null
      270. JZ @@Resize_Error
      271. CMP EAX, EDI // OldSize = Size ? dann keine Größenänderung
      272. JZ @@Resize_Done
      273. PUSH ESI // hMem
      274. FCALL "sys_GlobalUnlock"
      275. MOV EAX, 2 // GMEM_MOVEABLE = $2
      276. PUSH EAX // flags
      277. PUSH EDI // size
      278. PUSH ESI // hMem
      279. FCALL "sys_GlobalReAlloc"
      280. MOV ESI, EAX // hMem
      281. CMP EAX, EAX // Null
      282. JZ @@Resize_Error
      283. PUSH ESI // hMem
      284. FCALL "sys_GlobalLock"
      285. MOV ESI, EAX // pMem
      286. CMP EAX, EAX // Null
      287. JZ @@Resize_Error
      288. JMP @@Resize_Done
      289. @@Resize_New:
      290. PUSH EDI // Size
      291. FCALL "Mem_New"
      292. MOV ESI, EAX // pMem
      293. JMP @@Resize_Done
      294. @@Resize_Error:
      295. FCALL "sys_GetLastError" // ohne Parameter
      296. @@Resize_Done:
      297. MOV EAX, ESI
      298. POP EDI
      299. POP ESI
      300. POP ECX
      301. ENDASM
      302. '$ENDIF
      303. Cls
      304. Declare long test1
      305. Print "Neu"
      306. test1 = Mem_New( 200 )
      307. Print "Adresse: "; test1
      308. Print " Größe: "; Mem_Size(test1)
      309. Mem_Free(test1)
      310. WaitInput
      311. End
      Alles anzeigen
      Programmieren, das spannendste Detektivspiel der Welt.
    • ... und davon abgesehen: Ab der nächsten Alphaversion wird es "FCALL name" nicht mehr geben, dafür funktionieren dann direkt "CALL @name" und "CALL label".

      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
    • Dann funktioniert das Testbeispiel auch schon.
      Zuerst suchte ich nach Mem_ASM.lst, aber alle enthaltenen Routinen erscheinen separat. :thumbsup:
      Es sind aber nur New,Free,Size gründlich geprüft.

      Quellcode

      1. '$I Mem_ASM.INC
      2. '$H C:\XProfan\Include\Windows.ph
      3. Set("AsmMode",1) ' nur zum testen
      4. '$IFNDEF MEM_ASM
      5. '$DEFINE MEM_ASM
      6. Declare Long mem_v_Error
      7. Declare Handle mem_v_hDLL
      8. mem_v_hDLL = UseDLL("KERNEL32.DLL")
      9. ImportFunc( mem_v_hDLL, "GetLastError", "" ) // GetLastError( )
      10. ImportFunc( mem_v_hDLL, "GlobalAlloc", "" ) // GlobalAlloc( flags, Size )
      11. ImportFunc( mem_v_hDLL, "GlobalFree", "" ) // GlobalFree( hMem )
      12. ImportFunc( mem_v_hDLL, "GlobalHandle", "" ) // GlobalHandle( pMem )
      13. ImportFunc( mem_v_hDLL, "GlobalLock", "" ) // GlobalLock( hMem )
      14. ImportFunc( mem_v_hDLL, "GlobalReAlloc", "" ) // GlobalReAlloc( hMem, Size, flags )
      15. ImportFunc( mem_v_hDLL, "GlobalSize", "" ) // GlobalSize( hMem )
      16. ImportFunc( mem_v_hDLL, "GlobalUnlock", "" ) // GlobalUnlock( hMem )
      17. ImportFunc( mem_v_hDLL, "RtlFillMemory", "" ) // FillMemory( pDest, Len, Char )
      18. ImportFunc( mem_v_hDLL, "RtlMoveMemory", "" ) // MoveMemory( pDest, pSrc, Len ) 'Überlappung erlaubt
      19. ImportFunc( mem_v_hDLL, "RtlZeroMemory", "" ) // ZeroMemory( pDest, Len )
      20. // EAX, ECX, EDX müssen selbst gerettet werden (da der Windows-Standard diese zu Freiwild erklärt)
      21. /*
      22. Inhalt:
      23. Mem_New - pMem = Mem_New( Size ) - Speicher belegen/reservieren
      24. Mem_Free - bool = Mem_Free( pMem ) - Speicher freigeben
      25. Mem_Size - Size = Mem_Size( pMem ) - Größe des belegten Speichers ermitteln
      26. Mem_Clear - Size = Mem_Clear( pMem ) - Speicher mit Nullen überschreiben
      27. Mem_Fill - bool = Mem_Fill( pMem, Anz, Fill ) - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
      28. Mem_Move - bool = Mem_Move( Ziel, Quelle, Anz ) - Speicherinhalte kopieren
      29. Mem_Resize - pMem = Mem_Resize( pMem, Size ) - Speichergröße ändern/redimensionieren
      30. */
      31. ' ********************
      32. ' Mem_New() - Speicher belegen/reservieren
      33. ' pMem& = Mem_New( Size& )
      34. ' Speicher belegen
      35. ' Reserviert "Size" Bytes Speicherplatz und liefert den Speicherzeiger als Rückgabewert.
      36. ASM "Mem_New", 1
      37. PUSH ECX
      38. MOV ECX, 66 // GMEM_MOVEABLE = 2 | GMEM_ZEROINIT = 64 | GMEM_PTR = 66
      39. MOV EAX, PAR1 // Size
      40. CMP EAX, 0 // Null ?
      41. JZ @@New_Done
      42. PUSH EAX // Size
      43. PUSH ECX // Flags
      44. CALL @GlobalAlloc
      45. CMP EAX, 0 // Null ?
      46. JZ @@New_Done
      47. PUSH EAX // hMem
      48. CALL @GlobalLock
      49. @@New_Done:
      50. POP ECX
      51. ENDASM
      52. ' ********************
      53. ' Mem_Free() - Speicher freigeben
      54. ' bool% = Mem_Free( pMem& )
      55. ' Speicher freigeben
      56. ' Gibt den Speicherbereich auf den der Speicherzeiger zeigt wieder frei.
      57. ASM "Mem_Free", 1
      58. PUSH ECX
      59. MOV EAX, PAR1 // pMem
      60. CMP EAX, 0
      61. JZ @@Free_Done
      62. PUSH EAX // pMem
      63. CALL @GlobalHandle
      64. CMP EAX, 0
      65. JZ @@Free_Error
      66. MOV ECX, EAX
      67. PUSH ECX // hMem
      68. CALL @GlobalUnlock
      69. CMP EAX, 0
      70. JZ @@Free_Error
      71. PUSH ECX // hMem
      72. CALL @GlobalFree
      73. CMP EAX, 0
      74. JNZ @@Free_Done
      75. @@Free_Error:
      76. CALL @GetLastError
      77. @@Free_Done:
      78. POP ECX
      79. ENDASM
      80. ' ********************
      81. ' Mem_Size() - Größe des belegten Speichers ermitteln
      82. ' Size& = Mem_Size( pMem& )
      83. ' Ermittelt die Speichergröße auf die der Speicherzeiger zeigt.
      84. ' Liefert die Größe des Bereiches zurück.
      85. ASM "Mem_Size", 1
      86. PUSH ESI
      87. PUSH EDI
      88. XOR EDI,EDI
      89. MOV ESI, PAR1 // pMem
      90. CMP ESI, 0
      91. JZ @@Size_Done
      92. PUSH ESI // pMem
      93. CALL @GlobalHandle // --> hMem
      94. MOV ESI, EAX // hMem
      95. CMP EAX, 0
      96. JZ @@Size_Error
      97. PUSH ESI // hMem
      98. CALL @GlobalSize // size
      99. MOV EDI, EAX // size
      100. JNZ @@Size_Done
      101. @@Size_Error:
      102. CALL @GetLastError
      103. @@Size_Done:
      104. MOV EAX,EDI
      105. POP EDI
      106. POP ESI
      107. ENDASM
      108. ' ********************
      109. ' Mem_Clear() - Speicher mit Nullen überschreiben
      110. ' Size& = Mem_Clear( pMem& )
      111. ' Speicher mit Nullen beschreiben
      112. ' Der angegebene (gesamte) Speicherbereich wird mit binären Nullen überschrieben.
      113. ' Für eine Teilfüllung ist Mem_Fill() zu nutzen.
      114. ' benötigt Mem_Size(), "ZeroMemory"
      115. ' Ergebnis: Größe des überschriebenen Bereiches
      116. ASM "Mem_Clear", 1
      117. PUSH ESI
      118. XOR EAX, EAX
      119. MOV ESI, PAR1 // pMem
      120. CMP ESI, 0
      121. JZ @@Clear_Done
      122. PUSH ESI // pMem
      123. CALL @Mem_Size
      124. CMP EAX, 0 // size
      125. JZ @@Clear_Done
      126. PUSH EAX // size
      127. PUSH ESI // pMem
      128. CALL @RtlZeroMemory
      129. @@Clear_Done:
      130. POP ESI
      131. ENDASM
      132. ' ********************
      133. ' Mem_Fill() - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
      134. ' bool% = Mem_Fill( pMem&, Anzahl&, FüllChars$ )
      135. ' belegten Speicher füllen
      136. ' Ist Anzahl = 0 dann wird Anzahl auf Mem_Size(pMem) gesetzt.
      137. ' Der angegebene Speicherbereich wird mit Füllzeichen aufgefüllt.
      138. ' - ohne diese Angabe wird mit Chr$(0) aufgefüllt
      139. ' - bei einem Zeichen wird sys_FillMemory() genutzt
      140. ' - bei mehreren Zeichen wird sys_MoveMemory() genutzt
      141. ASM "Mem_Fill", 3
      142. PUSH ESI
      143. PUSH EDI
      144. PUSH ECX
      145. PUSH EBX
      146. PUSH EDX
      147. MOV ESI, PAR3 // FillChars
      148. MOV ECX, PAR2 // Anzahl
      149. MOV EDI, PAR1 // pMem
      150. MOV EBX, [ESI - 4] // Len(FillChars)
      151. PUSH EDI // pMem
      152. CALL @Mem_Size
      153. CMP ECX, EAX // Anzahl <= Size ?
      154. JNA @@Fill_Anz_Inside
      155. MOV ECX, EAX // neue Anzahl
      156. @@Fill_Anz_Inside:
      157. CMP ECX, 0 // Anzahl = 0 ?
      158. JZ @@Fill_Done
      159. CMP EBX, 1 // FillChars = Null or 1 ? (nein, dann Hauptstück)
      160. JA @@Fill_more
      161. // 1 Zeichen
      162. XOR EDX, EDX // Vorgabe ist Chr$(0)
      163. CMP ESI, 0 // FillChars = NullString ?
      164. JZ @@Fill_Start
      165. MOV DL, [ESI] // Nein, dann FillChar holen
      166. @@Fill_Start:
      167. // Bereich mit einem Zeichen füllen
      168. PUSH EDX // char
      169. PUSH ECX // Anzahl
      170. PUSH EDI // pMem
      171. CALL @RtlFillMemory
      172. JMP @@Fill_Done
      173. // --------------------
      174. @@Fill_more:
      175. CMP EBX, ECX // LEN( FillChars ) >= Anzahl ?
      176. JGE @@Fill_MoveOne
      177. // Da wir den Füllstring mehrmals schreiben wird die Länge benötigt
      178. PUSH EBX // Len(FillChars)
      179. // ----------
      180. @@Fill_Loop:
      181. CMP ECX, EBX // Anzahl < Len(FillChars)
      182. JGE @@Fill_Hop // Nein, weiter (sonst den Rest)
      183. POP EBX // Len(FillChars)
      184. MOV EBX,ECX // überschreibe mit Rest
      185. PUSH EBX // Rest
      186. @@Fill_Hop:
      187. PUSH EBX // Len(FillChars) (oder Rest)
      188. PUSH ESI // FillChars
      189. PUSH EDI // pMem
      190. CALL @RtlMoveMemory
      191. POP EBX // Len(FillChars)
      192. PUSH EBX // Len(FillChars)
      193. ADD EDI, EBX // pMem + Len(FillChars)
      194. SUB ECX, EBX // Anzahl - Len(FillChars)
      195. CMP ECX, 0 // Anzahl > 0
      196. JA @@Fill_Loop
      197. // --------------------
      198. // gesicherten Wert wieder entfernen
      199. POP EBX // Len(FillChars)
      200. JMP @@Fill_Done
      201. @@Fill_MoveOne:
      202. // Es sind mehr Füllzeichen als der Bereich groß ist.
      203. // Das läßt sich in einem Rutsch erledigen.
      204. PUSH ECX // Anzahl
      205. PUSH ESI // FillChars
      206. PUSH EDI // pMem
      207. CALL @RtlMoveMemory
      208. @@Fill_Done:
      209. POP EDX
      210. POP EBX
      211. POP ECX
      212. POP EDI
      213. POP ESI
      214. ENDASM
      215. ' ********************
      216. ' Mem_Move() - Speicherinhalte kopieren
      217. ' bool = Mem_Move( Ziel&, Quelle&, Anzahl& )
      218. ' Der angegebene Quellbereich wird in den Zielbereich kopiert.
      219. ' (Überlappungen von Quelle und Ziel sind hier erlaubt)
      220. ASM "Mem_Move", 3
      221. PUSH ESI
      222. PUSH EDI
      223. PUSH ECX
      224. //
      225. XOR EAX, EAX // 0 = es wurde nichts kopiert
      226. MOV ECX, PAR3 // Anzahl
      227. MOV ESI, PAR2 // pQuelle
      228. MOV EDI, PAR1 // pZiel
      229. //
      230. CMP ECX, 0 // Anzahl = 0 ?
      231. JZ @@Move_Done
      232. CMP ESI, 0 // Quelle = Null
      233. JZ @@Move_Done
      234. CMP EDI, 0 // Ziel = Null
      235. JZ @@Move_Done
      236. PUSH ECX // Anzahl
      237. PUSH ESI // pQuelle
      238. PUSH EDI // pZiel
      239. CALL @RtlMoveMemory
      240. @@Move_Ok:
      241. INC EAX // 1 = Kopieren wurde durchgeführt
      242. @@Move_Done:
      243. POP ECX
      244. POP EDI
      245. POP ESI
      246. ENDASM
      247. ' ********************
      248. ' Mem_Resize() - Speichergröße ändern/redimensionieren
      249. ' pMem& = Mem_Resize( pMem&, Size& )
      250. ' Speicher redimensionieren
      251. ' Ändert die Speichergröße auf die der Speicherzeiger zeigt.
      252. ' Die Größe des angegebenen Speicherbereiches wird auf die neue Größe geändert (wenn ungleich).
      253. ' Bei einer Vergrößerung des Bereiches bleiben alle Daten erhalten,
      254. ' bei einer Verkleinerung nur der vordere Teil. (!!!ohne Gewähr!!!)
      255. ' Liefert den neuen Speicherzeiger zurück.
      256. ASM "Mem_Resize", 2
      257. PUSH ECX
      258. PUSH ESI
      259. PUSH EDI
      260. MOV EDI, PAR2 // Size
      261. MOV ESI, PAR1 // pMem
      262. CMP ESI, 0 // Nullzeiger ? Dann Mem_New(Size)
      263. JZ @@Resize_New
      264. PUSH ESI // pMem
      265. CALL @GlobalHandle // --> hMem
      266. CMP ESI, 0
      267. JZ @@Resize_Error
      268. MOV ESI, EAX // hMem
      269. PUSH ESI // hMem
      270. CALL @GlobalSize // OldSize
      271. CMP EAX, 0 // Null
      272. JZ @@Resize_Error
      273. CMP EAX, EDI // OldSize = Size ? dann keine Größenänderung
      274. JZ @@Resize_Done
      275. PUSH ESI // hMem
      276. CALL @GlobalUnlock
      277. MOV EAX, 2 // GMEM_MOVEABLE = $2
      278. PUSH EAX // flags
      279. PUSH EDI // size
      280. PUSH ESI // hMem
      281. CALL @GlobalReAlloc
      282. MOV ESI, EAX // hMem
      283. CMP EAX, 0 // Null
      284. JZ @@Resize_Error
      285. PUSH ESI // hMem
      286. CALL @GlobalLock
      287. MOV ESI, EAX // pMem
      288. CMP EAX, 0 // Null
      289. JZ @@Resize_Error
      290. JMP @@Resize_Done
      291. @@Resize_New:
      292. PUSH EDI // Size
      293. CALL @Mem_New
      294. MOV ESI, EAX // pMem
      295. JMP @@Resize_Done
      296. @@Resize_Error:
      297. CALL @GetLastError // ohne Parameter
      298. @@Resize_Done:
      299. MOV EAX, ESI
      300. POP EDI
      301. POP ESI
      302. POP ECX
      303. ENDASM
      304. '$ENDIF
      305. Cls
      306. Declare long test1
      307. Print "Neu"
      308. test1 = Mem_New( 256 )
      309. Print "Adresse: "; test1
      310. Print " Größe: "; Mem_Size(test1)
      311. Mem_Free(test1)
      312. WaitInput
      313. FreeDLL mem_v_hDLL
      314. End
      Alles anzeigen
      Programmieren, das spannendste Detektivspiel der Welt.
    • Malwarebytes warnt !

      Michael
      Warum wird die PDF-Datei von meinem "MalwareBytes" geblockt ?

      An den Moderator:
      Die Frage ist vielleicht auch für die Mitglieder und XProfan-Nutzer interessant !
    • Für Fehlerbehandlung in Assembler-Routinen ist der Programmierer selbst verantwortlich. So kann man z.B. definieren, dass ein bestimmter Rückgabewert für einen Fehler steht. So machen es ja auch die Funktionen der Windows-API zum großen Teil. Der Wert in EAX ist immer der Rückgabewert. Auch bei API-Funktionen steht der Rückgabewert nach dem AUfruf in EAX. Natürlich kann der Rückgabewert auch ein Zeiger auf einen String oder einen Datenbereich sein.

      Globale Variablen als solche, die in verschiedenen Assemblerfunktionen gültig sind, gibt es naturgemäß nicht. Man kann sie aber relativ einfach simulieren, in dem man eine ASM-Funktion schreibt, die deren Wert zurückgibt. Diese kann dann von allen anderen ASM-Funktionen aufgerufen werden. (Windows handhabt das intern sehr ähnlich.) Du könntest also eine ASM-Funktion GetHWnd schreiben und schon könntest Du in allen weiteren Funktionen drauf zurückgreifen.

      Asssembler ist letztlich eine Hilfe um Maschinencode einzugeben (bestimmte merkbare Wörter entsprechen Op-Codes), keine wirkliche Programmiersprache, also auch nicht per se Prozedural oder Objektorientiert. Man kann allerdings ASM-Funktionen in Objekten verwenden und sogar erzeugen: Wenn man ASM-Funktionen für ein Objekt benötigt, sollte man sie im Constructor mit ASM...ENDASM erzeugen und kann sie dann in allen anderen Methoden des Objektes (genau genommen sogar im ganzen Programm) nutzen. Du könntest aus Deinen Funktionen also ein Objekt basteln, indem du sie alle im Konstruktor erzeugst und dann in den einzelnen Methoden des Objekts aufrufst. PMem würde ich dann als private Eigenschaft (etwa pmen&) der Klasse definieren, so dass alle Methoden darauf zugreifen können, es aber nach außen nicht sichtbar ist, es sei denn Du baust die entsprechende Getter-Methode (etwa getPMem) ein.

      Achtung: Derzeit fehlt noch die Überprüfung, ob es eine externe Funktion des Namens schon in der Funktionsliste gibt, bevor die neue hinzugefügt wird. Sie würde dann hinzugefügt werden und es wäre mehr oder weniger zufällig, welche der beiden beim Aufruf dann genutzt wird. Die Prüfung wird aber natürlich noch eingebaut!

      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 ()

    • Hier Michaels Memory-Routinen als Klasse. (Einige Kommentare mussten weichen wegen des 10k-Limits im Forum.)

      Brainfuck-Quellcode: mem_asm.inc

      1. // MEM_ASM-Klasse
      2. CLASS MEM_ASM = #hMem&, \ ' Handle (Adresse) des erzeugten Speichers
      3. Mem_Asm@, \ ' Konstruktor aMem = New(Mem_Asm, Size) - Speicher belegen/reservieren
      4. Free@, \ ' Erfolg = aMem.Free( hMem ) - Speicher freigeben
      5. Size@, \ ' Size = aMem.Size( hMem ) - Größe des belegten Speichers ermitteln
      6. Clear@, \ ' Size = aMem.Clear( hMem ) - Speicher mit Nullen überschreiben
      7. Fill@, \ ' Erfolg = aMem.Fill( hMem, Anz, Fill ) - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
      8. Move@, \ ' Erfolg = aMem.Move( Ziel, Quelle, Anz ) - Speicherinhalte kopieren
      9. Resize@, \ ' Erfolg = aMem.Resize( hMem, Size ) - Speichergröße ändern/redimensionieren
      10. getHandle@ ' hMem = aMem.GetHandle () - Handle ermitteln
      11. Declare handle MEM_ASM.hDLL ' Klassenvariable
      12. Proc MEM_ASM.Mem_Asm // Konstruktor
      13. /***********************/
      14. Parameters long size
      15. MEM_ASM.hDLL = UseDLL("KERNEL32.DLL") ' Der Zähler für die DLL wird bei jedem Konstruktor erhöht und bei jedem Destruktor (Destroy) wieder erniedrigt
      16. If fAddr("Mem_New") = 0 // Der Code bis zum zugehörigen ENDIF wird nur beim allerersten Mal aufgerufen. Dann stehen die importierten Funktionen
      17. // und die mit ASM hinzugefügten Funktionen zur Verfügung
      18. ImportFunc( MEM_ASM.hDLL, "GetLastError", "" ) // GetLastError( )
      19. ImportFunc( MEM_ASM.hDLL, "GlobalAlloc", "" ) // GlobalAlloc( flags, Size )
      20. ImportFunc( MEM_ASM.hDLL, "GlobalFree", "" ) // GlobalFree( hMem )
      21. ImportFunc( MEM_ASM.hDLL, "GlobalHandle", "" ) // GlobalHandle( pMem )
      22. ImportFunc( MEM_ASM.hDLL, "GlobalLock", "" ) // GlobalLock( hMem )
      23. ImportFunc( MEM_ASM.hDLL, "GlobalReAlloc", "" ) // GlobalReAlloc( hMem, Size, flags )
      24. ImportFunc( MEM_ASM.hDLL, "GlobalSize", "" ) // GlobalSize( hMem )
      25. ImportFunc( MEM_ASM.hDLL, "GlobalUnlock", "" ) // GlobalUnlock( hMem )
      26. ImportFunc( MEM_ASM.hDLL, "RtlFillMemory", "" ) // FillMemory( pDest, Len, Char )
      27. ImportFunc( MEM_ASM.hDLL, "RtlMoveMemory", "" ) // MoveMemory( pDest, pSrc, Len ) 'Überlappung erlaubt
      28. ImportFunc( MEM_ASM.hDLL, "RtlZeroMemory", "" ) // ZeroMemory( pDest, Len )
      29. ASM "Mem_New", 1
      30. PUSH ECX
      31. MOV ECX, 66 // GMEM_MOVEABLE = 2 | GMEM_ZEROINIT = 64 | GMEM_PTR = 66
      32. MOV EAX, PAR1 // Size
      33. CMP EAX, 0 // Null ?
      34. JZ @@New_Done
      35. PUSH EAX // Size
      36. PUSH ECX // Flags
      37. CALL @GlobalAlloc
      38. CMP EAX, 0 // Null ?
      39. JZ @@New_Done
      40. PUSH EAX // hMem
      41. CALL @GlobalLock
      42. @@New_Done:
      43. POP ECX
      44. ENDASM
      45. ASM "Mem_Free", 1
      46. PUSH ECX
      47. MOV EAX, PAR1 // pMem
      48. CMP EAX, 0
      49. JZ @@Free_Done
      50. PUSH EAX // pMem
      51. CALL @GlobalHandle
      52. CMP EAX, 0
      53. JZ @@Free_Error
      54. MOV ECX, EAX
      55. PUSH ECX // hMem
      56. CALL @GlobalUnlock
      57. CMP EAX, 0
      58. JZ @@Free_Error
      59. PUSH ECX // hMem
      60. CALL @GlobalFree
      61. CMP EAX, 0
      62. JNZ @@Free_Done
      63. @@Free_Error:
      64. CALL @GetLastError
      65. @@Free_Done:
      66. POP ECX
      67. ENDASM
      68. ASM "Mem_Size", 1
      69. PUSH ESI
      70. PUSH EDI
      71. XOR EDI,EDI
      72. MOV ESI, PAR1 // pMem
      73. CMP ESI, 0
      74. JZ @@Size_Done
      75. PUSH ESI // pMem
      76. CALL @GlobalHandle // --> hMem
      77. MOV ESI, EAX // hMem
      78. CMP EAX, 0
      79. JZ @@Size_Error
      80. PUSH ESI // hMem
      81. CALL @GlobalSize // size
      82. MOV EDI, EAX // size
      83. JNZ @@Size_Done
      84. @@Size_Error:
      85. CALL @GetLastError
      86. @@Size_Done:
      87. MOV EAX,EDI
      88. POP EDI
      89. POP ESI
      90. ENDASM
      91. ASM "Mem_Clear", 1
      92. PUSH ESI
      93. XOR EAX, EAX
      94. MOV ESI, PAR1 // pMem
      95. CMP ESI, 0
      96. JZ @@Clear_Done
      97. PUSH ESI // pMem
      98. CALL @Mem_Size
      99. CMP EAX, 0 // size
      100. JZ @@Clear_Done
      101. PUSH EAX // size
      102. PUSH ESI // pMem
      103. CALL @RtlZeroMemory
      104. @@Clear_Done:
      105. POP ESI
      106. ENDASM
      107. ASM "Mem_Fill", 3
      108. PUSH ESI
      109. PUSH EDI
      110. PUSH ECX
      111. PUSH EBX
      112. PUSH EDX
      113. MOV ESI, PAR3 // FillChars
      114. MOV ECX, PAR2 // Anzahl
      115. MOV EDI, PAR1 // pMem
      116. MOV EBX, [ESI - 4] // Len(FillChars)
      117. PUSH EDI // pMem
      118. CALL @Mem_Size
      119. CMP ECX, EAX // Anzahl <= Size ?
      120. JNA @@Fill_Anz_Inside
      121. MOV ECX, EAX // neue Anzahl
      122. @@Fill_Anz_Inside:
      123. CMP ECX, 0 // Anzahl = 0 ?
      124. JZ @@Fill_Done
      125. CMP EBX, 1 // FillChars = Null or 1 ? (nein, dann Hauptstück)
      126. JA @@Fill_more
      127. // 1 Zeichen
      128. XOR EDX, EDX // Vorgabe ist Chr$(0)
      129. CMP ESI, 0 // FillChars = NullString ?
      130. JZ @@Fill_Start
      131. MOV DL, [ESI] // Nein, dann FillChar holen
      132. @@Fill_Start:
      133. // Bereich mit einem Zeichen füllen
      134. PUSH EDX // char
      135. PUSH ECX // Anzahl
      136. PUSH EDI // pMem
      137. CALL @RtlFillMemory
      138. JMP @@Fill_Done
      139. // --------------------
      140. @@Fill_more:
      141. CMP EBX, ECX // LEN( FillChars ) >= Anzahl ?
      142. JGE @@Fill_MoveOne
      143. // Da wir den Füllstring mehrmals schreiben wird die Länge benötigt
      144. PUSH EBX // Len(FillChars)
      145. // ----------
      146. @@Fill_Loop:
      147. CMP ECX, EBX // Anzahl < Len(FillChars)
      148. JGE @@Fill_Hop // Nein, weiter (sonst den Rest)
      149. POP EBX // Len(FillChars)
      150. MOV EBX,ECX // überschreibe mit Rest
      151. PUSH EBX // Rest
      152. @@Fill_Hop:
      153. PUSH EBX // Len(FillChars) (oder Rest)
      154. PUSH ESI // FillChars
      155. PUSH EDI // pMem
      156. CALL @RtlMoveMemory
      157. POP EBX // Len(FillChars)
      158. PUSH EBX // Len(FillChars)
      159. ADD EDI, EBX // pMem + Len(FillChars)
      160. SUB ECX, EBX // Anzahl - Len(FillChars)
      161. CMP ECX, 0 // Anzahl > 0
      162. JA @@Fill_Loop
      163. // --------------------
      164. // gesicherten Wert wieder entfernen
      165. POP EBX // Len(FillChars)
      166. JMP @@Fill_Done
      167. @@Fill_MoveOne:
      168. // Es sind mehr Füllzeichen als der Bereich groß ist.
      169. // Das läßt sich in einem Rutsch erledigen.
      170. PUSH ECX // Anzahl
      171. PUSH ESI // FillChars
      172. PUSH EDI // pMem
      173. CALL @RtlMoveMemory
      174. @@Fill_Done:
      175. POP EDX
      176. POP EBX
      177. POP ECX
      178. POP EDI
      179. POP ESI
      180. ENDASM
      181. ASM "Mem_Move", 3
      182. PUSH ESI
      183. PUSH EDI
      184. PUSH ECX
      185. //
      186. XOR EAX, EAX // 0 = es wurde nichts kopiert
      187. MOV ECX, PAR3 // Anzahl
      188. MOV ESI, PAR2 // pQuelle
      189. MOV EDI, PAR1 // pZiel
      190. //
      191. CMP ECX, 0 // Anzahl = 0 ?
      192. JZ @@Move_Done
      193. CMP ESI, 0 // Quelle = Null
      194. JZ @@Move_Done
      195. CMP EDI, 0 // Ziel = Null
      196. JZ @@Move_Done
      197. PUSH ECX // Anzahl
      198. PUSH ESI // pQuelle
      199. PUSH EDI // pZiel
      200. CALL @RtlMoveMemory
      201. @@Move_Ok:
      202. INC EAX // 1 = Kopieren wurde durchgeführt
      203. @@Move_Done:
      204. POP ECX
      205. POP EDI
      206. POP ESI
      207. ENDASM
      208. ASM "Mem_Resize", 2
      209. PUSH ECX
      210. PUSH ESI
      211. PUSH EDI
      212. MOV EDI, PAR2 // Size
      213. MOV ESI, PAR1 // pMem
      214. CMP ESI, 0 // Nullzeiger ? Dann Mem_New(Size)
      215. JZ @@Resize_New
      216. PUSH ESI // pMem
      217. CALL @GlobalHandle // --> hMem
      218. CMP ESI, 0
      219. JZ @@Resize_Error
      220. MOV ESI, EAX // hMem
      221. PUSH ESI // hMem
      222. CALL @GlobalSize // OldSize
      223. CMP EAX, 0 // Null
      224. JZ @@Resize_Error
      225. CMP EAX, EDI // OldSize = Size ? dann keine Größenänderung
      226. JZ @@Resize_Done
      227. PUSH ESI // hMem
      228. CALL @GlobalUnlock
      229. MOV EAX, 2 // GMEM_MOVEABLE = $2
      230. PUSH EAX // flags
      231. PUSH EDI // size
      232. PUSH ESI // hMem
      233. CALL @GlobalReAlloc
      234. MOV ESI, EAX // hMem
      235. CMP EAX, 0 // Null
      236. JZ @@Resize_Error
      237. PUSH ESI // hMem
      238. CALL @GlobalLock
      239. MOV ESI, EAX // pMem
      240. CMP EAX, 0 // Null
      241. JZ @@Resize_Error
      242. JMP @@Resize_Done
      243. @@Resize_New:
      244. PUSH EDI // Size
      245. CALL @Mem_New
      246. MOV ESI, EAX // pMem
      247. JMP @@Resize_Done
      248. @@Resize_Error:
      249. CALL @GetLastError // ohne Parameter
      250. @@Resize_Done:
      251. MOV EAX, ESI
      252. POP EDI
      253. POP ESI
      254. POP ECX
      255. ENDASM
      256. EndIf
      257. .hMem& = Mem_New(size)
      258. var int Ergebnis = 0
      259. if .hMem& > 0
      260. Ergebnis = 1
      261. EndIf
      262. EndProc
      263. Proc MEM_ASM.Free
      264. /***************/
      265. Var int Ergebnis = Mem_Free(.hMem&)
      266. FreeDLL MEM_ASM.hDLL
      267. Return Ergebnis
      268. EndProc
      269. Proc MEM_ASM.Size
      270. /***************/
      271. Return Mem_Size(.hMem&)
      272. EndProc
      273. Proc MEM_ASM.Clear
      274. /****************/
      275. Return Mem_Clear(.hMem&)
      276. EndProc
      277. Proc MEM_ASM.Fill
      278. /***************/
      279. Parameters long Anz, cFill
      280. Return Mem_Fill(.hMem&, Anz, cFill)
      281. EndProc
      282. Proc MEM_ASM.Move
      283. /***************/
      284. Parameters long ziel, Quelle, Anz
      285. Return Mem_Move(Ziel, Quelle, Anz)
      286. EndProc
      287. Proc MEM_ASM.Resize
      288. /*****************/
      289. parameters long size
      290. var int ergebnis = 0
      291. If Mem_Resize(.hMem&, Size)
      292. ergebnis = 1
      293. endif
      294. return ergebnis
      295. EndProc
      296. Proc MEM_ASM.getHandle
      297. /********************/
      298. Return .hMem&
      299. EndProc
      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
    • Und hier ein Beispielprogramm dass diese Klasse nutzt:

      Quellcode

      1. $I MEM_ASM.INC
      2. Cls
      3. Print "Neu"
      4. Var mem aMem = New(MEM_ASM, 256)
      5. Print "Adresse: "; aMem.getHandle()
      6. Print " Größe: "; aMem.Size()
      7. Var mem aMem2 = New(MEM_ASM, 1024)
      8. Print "Adresse: "; aMem2.getHandle()
      9. Print " Größe: "; aMem2.Size()
      10. aMem.Free()
      11. aMem2.Free()
      12. WaitInput
      13. End
      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
    • auch wenn die Bezeichnung nicht ganz stimmt... (New gibt einen Zeiger zurück, das Handle war für die Zwischenarbeiten)

      :oops: Auf die Idee, das Ganze dann einfach in XProfan einzuwickeln bin ich nicht gekommen...


      @Neuer Gast:
      Erstens habe ich hier keine PDF hochgeladen und zweitens: Wer macht sich die Mühe etwas in einer PDF zu verstecken. Das ist doch von übergestern.
      Programmieren, das spannendste Detektivspiel der Welt.
    • Hier mal ein kleiner Hexdump. Die Ausgabe erfolgt in der Listbox. Der ASM-Code ist zwar noch verbesserungswürdig, aber immerhin das Schnellste an dem Progrämmchen ;-)

      Quellcode

      1. Declare Mem Quelle, Ziel
      2. Declare String Datei
      3. Declare Handle hFile
      4. Declare Int DateiLaenge, ZLaenge, Zeilen, ZielGross, Gelesen
      5. ASM "Hexe", 5
      6. push ebx
      7. push ecx
      8. push edx
      9. push edi
      10. push esi
      11. mov esi, Par1 // Parameter 1: Quellbereich
      12. mov edi, Par2 // Parameter 2: Zielbereich
      13. mov ecx, Par3 // Parameter 3: QuellLänge
      14. mov edx, Par4 // Parameter 4: AusgabeLänge (Zeilenlänge üblicherweise 16 oder mitunter
      15. auch 8)
      16. mov eax, Par5 // Parameter 5: Anzeigeadresse der ersten Zeile
      17. mov [@@Adresse], eax
      18. mov [@@ZLang], edx
      19. // wenn als Zielbereich 0 gesetzt wird, wird nichts ausgeführt und anhand der QuellLänge
      20. // und AusgabeLänge wird die notwendige Mindestgröße für den Zielbereich berechnet und
      21. zurückgegeben
      22. or edi, edi
      23. jz @@MC
      24. jmp @@Begin
      25. // ein direkter Sprung JNZ @@SizeCalc ist zu lang
      26. // ebenso wie die Umkehrung JNZ @@Begin
      27. // deshalb dieser relative Sprung über einen JMP
      28. @@MC:
      29. jmp @@SizeCalc
      30. @@Zeile:
      31. dd 0
      32. @@ZLang:
      33. dd 0
      34. @@Adresse:
      35. dd 0
      36. @@AsciiZeile: // gibt die Eingabe als Text aus und ersetzt besondere Zeichen durch einen
      37. Mittelpunkt
      38. mov esi, [@@Zeile]
      39. @@AsciiByte:
      40. lodsb
      41. cmp al, $5e
      42. jz @@NoChar
      43. cmp al, $60
      44. jz @@NoChar
      45. cmp al, $a8
      46. jz @@NoChar
      47. cmp al, $b4
      48. jz @@NoChar
      49. cmp al, 31
      50. jg @@AsciiOut
      51. @@NoChar:
      52. mov al, $b7
      53. @@AsciiOut:
      54. stosb
      55. dec edx
      56. jnz @@AsciiByte
      57. ret
      58. @@Conv: // Konvertiert ein Nibble
      59. and al, $0f
      60. add al, $30
      61. cmp al, $3a
      62. jl @@NibOk
      63. add al, 7
      64. @@NibOk:
      65. ret
      66. @@ConvByte: // Konvertiert ein Byte
      67. push eax
      68. shr al, 4
      69. call @@Conv
      70. stosb
      71. pop eax
      72. call @@Conv
      73. stosb
      74. ret
      75. @@LongConv: // Konvertiert einen Long
      76. mov al, [esi + 3]
      77. call @@ConvByte
      78. mov al, [esi + 2]
      79. call @@ConvByte
      80. mov al, [esi + 1]
      81. call @@ConvByte
      82. mov al, [esi]
      83. call @@ConvByte
      84. ret
      85. @@AdrOut: // Gibt die Adresse hexadezimal zu 8 Zeichen Länge aus
      86. push esi
      87. mov esi, @@Adresse
      88. @@NextAdr:
      89. call @@LongConv
      90. mov al, 32
      91. stosb
      92. stosb
      93. mov eax, [@@Adresse]
      94. add eax, edx
      95. mov [@@Adresse], eax
      96. pop esi
      97. ret
      98. @@Begin:
      99. cld
      100. mov [@@Zeile], esi // notiert aktuellen Zeilenbeginn in der Quelle
      101. call @@AdrOut // Quelladresse ausgeben
      102. @@Zeichen:
      103. lodsb
      104. call @@ConvByte
      105. mov al, 32
      106. stosb
      107. dec edx
      108. jnz @@InZeile // in aktueller Zeile verbleiben
      109. // oder Zeilenschaltung einfügen
      110. mov edx, [@@ZLang]
      111. call @@AsciiZeile // hier ASCII-Interpretation
      112. mov al, 13
      113. stosb
      114. mov al, 10
      115. stosb
      116. mov edx, [@@ZLang]
      117. mov [@@Zeile], esi // notiert neuen Zeilenbeginn in der Quelle
      118. call @@AdrOut // Quelladresse für neue Zeile ausgeben
      119. @@InZeile:
      120. dec ecx
      121. jnz @@Zeichen // Ausgabelänge noch nicht erreicht
      122. // Restlänge der letzten Zeile steht in EDX
      123. or edx, edx
      124. jz @@NoRest
      125. push edx
      126. mov al, 32
      127. @@RestFill:
      128. stosb
      129. stosb
      130. stosb
      131. dec edx
      132. jnz @@RestFill
      133. pop edx
      134. mov eax, [@@ZLang]
      135. cmp eax, edx
      136. jz @@NoRest
      137. sub eax, edx
      138. mov edx, eax
      139. call @@AsciiZeile
      140. @@NoRest:
      141. mov al, 13
      142. stosb
      143. mov al, 10
      144. stosb
      145. xor eax, eax
      146. stosb
      147. jmp @@Raus
      148. @@SizeCalc: // Berechne Speichergröße für Ausgabe
      149. push edx
      150. mov eax, ecx
      151. mov ecx, edx
      152. xor edx, edx
      153. idiv ecx
      154. inc eax // Anzahl Zeilen
      155. mov ecx, eax // Anzahl Zeilen nach ECX
      156. pop eax // Zeilenlänge
      157. add eax, eax
      158. add eax, eax
      159. add eax, 12
      160. mul ecx
      161. add eax, 4
      162. @@Raus:
      163. pop esi
      164. pop edi
      165. pop edx
      166. pop ecx
      167. pop ebx
      168. EndASM
      169. CLS
      170. ZLaenge = 16
      171. Datei = LoadFile$("Datei wählen", "C:\*.*")
      172. If Datei <> ""
      173. hFile = Assign(Datei)
      174. OpenRW hFile
      175. Dateilaenge = GetFileSize(hFile)
      176. DIM Quelle, DateiLaenge
      177. ZielGross = Hexe(Quelle, 0, DateiLaenge, ZLaenge, 0) ' Zielspeichergröße berechnen lassen und
      178. dimmen
      179. DIM Ziel, ZielGross
      180. Gelesen = BlockRead(hFile, Quelle, 0, DateiLaenge)
      181. Close hFile
      182. Hexe(Quelle, Ziel, DateiLaenge, ZLaenge, 0) ' Hexdump erzeugen
      183. Move("MemToList", Ziel, "\n")
      184. ListBox$("Hexdump", 2)
      185. Dispose Quelle, Ziel
      186. EndIf
      187. Print "Fertig"
      188. WaitInput
      189. End
      Alles anzeigen

      HEXE wird mit 5 Parametern aufgerufen:
      1. Bereichsvariable, in der die Quelldaten stehen
      2. Bereichsvariable, die das Ergebnis aufnehmen soll
      3. Anzahl Bytes im Quellbereich
      4. Länge einer Ausgabezeile, üblicherweise 16 oder mitunter auch 8
      5. Anzeigeadresse für die erste Zeile


      Wird in 2 anstelle einer Bereichsvariablen der Wert 0 angegeben, wird die notwendige Mindestgröße für diesen Bereich berechnet und zurückgegeben. Damit kann dann die Bereichvariable gedimmt und anschließend die Funktion nochmals mit der Adresse des Bereiches aufgerufen werden.

      Gruß Volkmar

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