ProcAddr liefert derzeit Fehlermeldung ...
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 ...
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ß
RolandIntel 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:
Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von p. specht ()
-
Mit Erlaubnis von RGH darf ich ein vorläufiges Merkblatt zum aktuellen Ausbaustand des RGH-XProfan-Inlineassemblers (RGH-"XASM") veröffentlichen. Na dann "Gut Netzausfall und Plattencrash!"
Gruss -
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
- WindowTitle "Selbsterforschung"
- WindowStyle 24:Window 0,0-%maxx,%maxy:showmax
- set("AsmMode",2):font 2
- ASM "Test2",1:data:
- mov ebx,par1:mov ecx,data:add ecx,ebx:xor eax,eax:mov al,[ecx]:exyt:
- ENDASM
- whileloop -3,-1
- print right$("0"+hex$(test2(&Loop)),2); '55 89 E5 = Pgm-Start
- endwhile
- whileloop 14,19
- print right$("0"+hex$(test2(&Loop)),2); '89 EC 5D C2 (= Pgm-Ende)+ 04 00 (= 0004/4 = 1 Parameter)
- endwhile
- clearclip
- whileloop -3,19
- print right$("0"+hex$(test2(&Loop)),2); 'Programm
- putclip right$("0"+hex$(test2(&Loop)),2)
- endwhile
- print:print "\n ASM-PGM Hex-Bytecode im Clipboard"
- Waitinput 15000
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
- Declare String s1, s2
- s1 = "Hallo \z"
- s2 = "Welt\z"
- Cls
- ASM "api_strcat", 2
- MOV ESI, Par1
- MOV EDI, Par2
- CALL strcat
- strcat:
- XOR ECX,ECX
- MOV EBP,ESI
- lp1:
- LODSB
- OR AL,AL
- JZ lp1d
- INC ECX
- JMP lp1
- lp1d:
- MOV ESI,EDI
- MOV EBX,ECX
- lp2:
- LODSB
- OR AL,AL
- JZ lp2d
- MOV [EBP+EBX],AL
- INC EBX
- JMP lp2
- XOR AL,AL
- MOV [EBP+EBX],AL
- lp2d:
- ENDASM
- Print api_strcat(s1, s2)
- WaitKey
- End
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 -
Danke für die Erläuterungen.
Ich denke, ich schaue mir künftig lieber Rolands
Beispielcodes statt fremde Codes an.
Das bringt mir mehr.
Ich hoffe, daß hier in die Rubrik noch einige
Beispiele kommen. -
So, habe nun auch eine Version fertig. StrCat könnte man etwa so machen
Quellcode
- Declare String s1, s2
- s1 = "Hall0 \z"
- s2 = "Welt\z"
- s1 = s1 + Space$(Len(s2)) ' String verlängern, um Ziel aufzunehmen
- Cls
- ASM "api_strcat", 2
- MOV ESI, Par1
- MOV EDI, Par2
- CLD // directionflag setzen, man weiß ja nie, wie es gerade steht :-)
- lp1:
- LODSB
- OR AL,AL
- JNZ lp1
- lp1d:
- DEC ESI
- XCHG ESI, EDI
- // Quelle und Ziel tauschen, da wir jetzt in Par1 schreiben wollen
- lp2:
- LODSB
- STOSB
- OR AL,AL
- JZ lp2d
- JMP lp2
- XOR AL,AL
- MOVSB
- lp2d:
- ENDASM
- Print api_strcat(s1, s2)
- Print Trim$(s1)+ "!!"
- WaitKey
- End
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 wirdDieser 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
- '$I Mem_ASM.INC
- '$H C:\XProfan\Include\Windows.ph
- '$IFNDEF MEM_ASM
- '$DEFINE MEM_ASM
- Declare Handle mwmem_hDLL
- mwmem_hDLL = UseDLL("KERNEL32.DLL")
- ImportFunc( mwmem_hDLL, "GetLastError", "sys_GetLastError" ) // GetLastError( )
- ImportFunc( mwmem_hDLL, "GlobalAlloc", "sys_GlobalAlloc" ) // GlobalAlloc( flags, Size )
- ImportFunc( mwmem_hDLL, "GlobalFree", "sys_GlobalFree" ) // GlobalFree( hMem )
- ImportFunc( mwmem_hDLL, "GlobalHandle", "sys_GlobalHandle" ) // GlobalHandle( pMem )
- ImportFunc( mwmem_hDLL, "GlobalLock", "sys_GlobalLock" ) // GlobalLock( hMem )
- ImportFunc( mwmem_hDLL, "GlobalReAlloc", "sys_GlobalReAlloc" ) // GlobalReAlloc( hMem, Size, flags )
- ImportFunc( mwmem_hDLL, "GlobalSize", "sys_GlobalSize" ) // GlobalSize( hMem )
- ImportFunc( mwmem_hDLL, "GlobalUnlock", "sys_GlobalUnlock" ) // GlobalUnlock( hMem )
- ImportFunc( mwmem_hDLL, "RtlFillMemory", "sys_FillMemory" ) // FillMemory( pDest, Len, Char )
- ImportFunc( mwmem_hDLL, "RtlMoveMemory", "sys_MoveMemory" ) // MoveMemory( pDest, pSrc, Len ) 'Überlappung erlaubt
- ImportFunc( mwmem_hDLL, "RtlZeroMemory", "sys_ZeroMemory" ) // ZeroMemory( pDest, Len )
- // EAX, ECX, EDX müssen selbst gerettet werden (da der Windows-Standard diese zu Freiwild erklärt)
- /*
- Inhalt:
- Mem_New - pMem = Mem_New( Size ) - Speicher belegen/reservieren
- Mem_Free - bool = Mem_Free( pMem ) - Speicher freigeben
- Mem_Size - Size = Mem_Size( pMem ) - Größe des belegten Speichers ermitteln
- Mem_Clear - Size = Mem_Clear( pMem ) - Speicher mit Nullen überschreiben
- Mem_Fill - bool = Mem_Fill( pMem, Anz, Fill ) - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
- Mem_Move - bool = Mem_Move( Ziel, Quelle, Anz ) - Speicherinhalte kopieren
- Mem_Resize - pMem = Mem_Resize( pMem, Size ) - Speichergröße ändern/redimensionieren
- */
- ' ********************
- ' Mem_New() - Speicher belegen/reservieren
- ' pMem& = Mem_New( Size& )
- ' Speicher belegen
- ' Reserviert "Size" Bytes Speicherplatz und liefert den Speicherzeiger als Rückgabewert.
- ASM "Mem_New", 1
- PUSH ECX
- MOV ECX, 66 // GMEM_MOVEABLE = 2 | GMEM_ZEROINIT = 64 | GMEM_PTR = 66
- MOV EAX, PAR1 // Size
- CMP EAX, EAX // Null ?
- JZ @@New_Done
- PUSH EAX // Size
- PUSH ECX // Flags
- FCALL "sys_GlobalAlloc"
- CMP EAX, EAX // Null ?
- JZ @@New_Done
- PUSH EAX // hMem
- FCALL "sys_GlobalLock"
- @@New_Done:
- POP ECX
- ENDASM
- ' ********************
- ' Mem_Free() - Speicher freigeben
- ' bool% = Mem_Free( pMem& )
- ' Speicher freigeben
- ' Gibt den Speicherbereich auf den der Speicherzeiger zeigt wieder frei.
- ASM "Mem_Free", 1
- PUSH ECX
- MOV EAX, PAR1 // pMem
- CMP EAX, EAX
- JZ @@Free_Done
- PUSH EAX // pMem
- FCALL "sys_GlobalHandle"
- CMP EAX, EAX
- JZ @@Free_Error
- MOV ECX, EAX
- PUSH ECX // hMem
- FCALL "sys_GlobalUnlock"
- CMP EAX, EAX
- JZ @@Free_Error
- PUSH ECX // hMem
- FCALL "sys_GlobalFree"
- CMP EAX, EAX
- JNZ @@Free_Done
- @@Free_Error:
- FCALL "sys_GetLastError"
- @@Free_Done:
- POP ECX
- ENDASM
- ' ********************
- ' Mem_Size() - Größe des belegten Speichers ermitteln
- ' Size& = Mem_Size( pMem& )
- ' Ermittelt die Speichergröße auf die der Speicherzeiger zeigt.
- ' Liefert die Größe des Bereiches zurück.
- ASM "Mem_Size", 1
- PUSH ESI
- PUSH EDI
- XOR EDI,EDI
- MOV ESI, PAR1 // pMem
- CMP ESI, ESI
- JZ @@Size_Done
- PUSH ESI // pMem
- FCALL "sys_GlobalHandle" // --> hMem
- MOV ESI, EAX // hMem
- CMP EAX, EAX
- JZ @@Size_Error
- PUSH ESI // hMem
- FCALL "sys_GlobalSize" // size
- MOV EDI, EAX // size
- JNZ @@Size_Done
- @@Size_Error:
- FCALL "sys_GetLastError"
- @@Size_Done:
- MOV EAX,EDI
- POP EDI
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Clear() - Speicher mit Nullen überschreiben
- ' Size& = Mem_Clear( pMem& )
- ' Speicher mit Nullen beschreiben
- ' Der angegebene (gesamte) Speicherbereich wird mit binären Nullen überschrieben.
- ' Für eine Teilfüllung ist Mem_Fill() zu nutzen.
- ' benötigt Mem_Size(), "ZeroMemory"
- ' Ergebnis: Größe des überschriebenen Bereiches
- ASM "Mem_Clear", 1
- PUSH ESI
- XOR EAX, EAX
- MOV ESI, PAR1 // pMem
- CMP ESI, ESI
- JZ @@Clear_Done
- PUSH ESI // pMem
- FCALL "Mem_Size"
- CMP EAX, EAX // size
- JZ @@Clear_Done
- PUSH EAX // size
- PUSH ESI // pMem
- FCALL "sys_ZeroMemory"
- @@Clear_Done:
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Fill() - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
- ' bool% = Mem_Fill( pMem&, Anzahl&, FüllChars$ )
- ' belegten Speicher füllen
- ' Ist Anzahl = 0 dann wird Anzahl auf Mem_Size(pMem) gesetzt.
- ' Der angegebene Speicherbereich wird mit Füllzeichen aufgefüllt.
- ' - ohne diese Angabe wird mit Chr$(0) aufgefüllt
- ' - bei einem Zeichen wird sys_FillMemory() genutzt
- ' - bei mehreren Zeichen wird sys_MoveMemory() genutzt
- ASM "Mem_Fill", 3
- PUSH ESI
- PUSH EDI
- PUSH ECX
- PUSH EBX
- PUSH EDX
- MOV ESI, PAR3 // FillChars
- MOV ECX, PAR2 // Anzahl
- MOV EDI, PAR1 // pMem
- MOV EBX, [ESI - 4] // Len(FillChars)
- PUSH EDI // pMem
- FCALL "Mem_Size"
- CMP ECX, EAX // Anzahl <= Size ?
- JBE @@Fill_Anz_Inside
- MOV ECX, EAX // neue Anzahl
- @@Fill_Anz_Inside:
- CMP ECX, ECX // Anzahl = 0 ?
- JZ @@Fill_Done
- CMP EBX, 1 // FillChars = Null or 1 ? (nein, dann Hauptstück)
- JA @@Fill_more
- // 1 Zeichen
- XOR EDX, EDX // Vorgabe ist Chr$(0)
- CMP ESI, ESI // FillChars = NullString ?
- JZ @@Fill_Start
- MOV DL, [ESI] // Nein, dann FillChar holen
- @@Fill_Start:
- // Bereich mit einem Zeichen füllen
- PUSH EDX // char
- PUSH ECX // Anzahl
- PUSH EDI // pMem
- FCALL "sys_FillMemory"
- JMP @@Fill_Done
- // --------------------
- @@Fill_more:
- CMP EBX, ECX // LEN( FillChars ) >= Anzahl ?
- JAE @@Fill_MoveOne
- // Da wir den Füllstring mehrmals schreiben wird die Länge benötigt
- PUSH EBX // Len(FillChars)
- // ----------
- @@Fill_Loop:
- CMP ECX, EBX // Anzahl < Len(FillChars)
- JAE @@Fill_Hop // Nein, weiter (sonst den Rest)
- POP EBX // Len(FillChars)
- MOV EBX,ECX // überschreibe mit Rest
- PUSH EBX // Rest
- @@Fill_Hop:
- PUSH EBX // Len(FillChars) (oder Rest)
- PUSH ESI // FillChars
- PUSH EDI // pMem
- FCALL "sys_MoveMemory"
- POP EBX // Len(FillChars)
- PUSH EBX // Len(FillChars)
- ADD EDI, EBX // pMem + Len(FillChars)
- SUB ECX, EBX // Anzahl - Len(FillChars)
- CMP ECX, ECX // Anzahl > 0
- JA @@Fill_Loop
- // --------------------
- // gesicherten Wert wieder entfernen
- POP EBX // Len(FillChars)
- JMP @@Fill_Done
- @@Fill_MoveOne:
- // Es sind mehr Füllzeichen als der Bereich groß ist.
- // Das läßt sich in einem Rutsch erledigen.
- PUSH ECX // Anzahl
- PUSH ESI // FillChars
- PUSH EDI // pMem
- FCALL "sys_MoveMemory"
- @@Fill_Done:
- POP EDX
- POP EBX
- POP ECX
- POP EDI
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Move() - Speicherinhalte kopieren
- ' bool = Mem_Move( Ziel&, Quelle&, Anzahl& )
- ' Der angegebene Quellbereich wird in den Zielbereich kopiert.
- ' (Überlappungen von Quelle und Ziel sind hier erlaubt)
- ASM "Mem_Move", 3
- PUSH ESI
- PUSH EDI
- PUSH ECX
- //
- XOR EAX, EAX // 0 = es wurde nichts kopiert
- MOV ECX, PAR3 // Anzahl
- MOV ESI, PAR2 // pQuelle
- MOV EDI, PAR1 // pZiel
- //
- CMP ESI, ESI // Anzahl = 0 ?
- JZ @@Move_Done
- CMP ESI, ESI // Quelle = Null
- JZ @@Move_Done
- CMP EDI, EDI // Ziel = Null
- JZ @@Move_Done
- PUSH ECX // Anzahl
- PUSH ESI // pQuelle
- PUSH EDI // pZiel
- FCALL "sys_MoveMemory"
- @@Move_Ok:
- INC EAX // 1 = Kopieren wurde durchgeführt
- @@Move_Done:
- POP ECX
- POP EDI
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Resize() - Speichergröße ändern/redimensionieren
- ' pMem& = Mem_Resize( pMem&, Size& )
- ' Speicher redimensionieren
- ' Ändert die Speichergröße auf die der Speicherzeiger zeigt.
- ' Die Größe des angegebenen Speicherbereiches wird auf die neue Größe geändert (wenn ungleich).
- ' Bei einer Vergrößerung des Bereiches bleiben alle Daten erhalten,
- ' bei einer Verkleinerung nur der vordere Teil. (!!!ohne Gewähr!!!)
- ' Liefert den neuen Speicherzeiger zurück.
- ASM "Mem_Resize", 2
- PUSH ECX
- PUSH ESI
- PUSH EDI
- MOV EDI, PAR2 // Size
- MOV ESI, PAR1 // pMem
- CMP ESI, ESI // Nullzeiger ? Dann Mem_New(Size)
- JZ @@Resize_New
- PUSH ESI // pMem
- FCALL "sys_GlobalHandle" // --> hMem
- CMP ESI, ESI
- JZ @@Resize_Error
- MOV ESI, EAX // hMem
- PUSH ESI // hMem
- FCALL "sys_GlobalSize" // OldSize
- CMP EAX, EAX // Null
- JZ @@Resize_Error
- CMP EAX, EDI // OldSize = Size ? dann keine Größenänderung
- JZ @@Resize_Done
- PUSH ESI // hMem
- FCALL "sys_GlobalUnlock"
- MOV EAX, 2 // GMEM_MOVEABLE = $2
- PUSH EAX // flags
- PUSH EDI // size
- PUSH ESI // hMem
- FCALL "sys_GlobalReAlloc"
- MOV ESI, EAX // hMem
- CMP EAX, EAX // Null
- JZ @@Resize_Error
- PUSH ESI // hMem
- FCALL "sys_GlobalLock"
- MOV ESI, EAX // pMem
- CMP EAX, EAX // Null
- JZ @@Resize_Error
- JMP @@Resize_Done
- @@Resize_New:
- PUSH EDI // Size
- FCALL "Mem_New"
- MOV ESI, EAX // pMem
- JMP @@Resize_Done
- @@Resize_Error:
- FCALL "sys_GetLastError" // ohne Parameter
- @@Resize_Done:
- MOV EAX, ESI
- POP EDI
- POP ESI
- POP ECX
- ENDASM
- '$ENDIF
- Cls
- Declare long test1
- Print "Neu"
- test1 = Mem_New( 200 )
- Print "Adresse: "; test1
- Print " Größe: "; Mem_Size(test1)
- Mem_Free(test1)
- WaitInput
- End
Programmieren, das spannendste Detektivspiel der Welt. -
Bei FCALL wird der Funktionsname OHNE Anführungszeichen angegeben!
Gruß
RolandIntel 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 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ß
RolandIntel 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.
Es sind aber nur New,Free,Size gründlich geprüft.
Quellcode
- '$I Mem_ASM.INC
- '$H C:\XProfan\Include\Windows.ph
- Set("AsmMode",1) ' nur zum testen
- '$IFNDEF MEM_ASM
- '$DEFINE MEM_ASM
- Declare Long mem_v_Error
- Declare Handle mem_v_hDLL
- mem_v_hDLL = UseDLL("KERNEL32.DLL")
- ImportFunc( mem_v_hDLL, "GetLastError", "" ) // GetLastError( )
- ImportFunc( mem_v_hDLL, "GlobalAlloc", "" ) // GlobalAlloc( flags, Size )
- ImportFunc( mem_v_hDLL, "GlobalFree", "" ) // GlobalFree( hMem )
- ImportFunc( mem_v_hDLL, "GlobalHandle", "" ) // GlobalHandle( pMem )
- ImportFunc( mem_v_hDLL, "GlobalLock", "" ) // GlobalLock( hMem )
- ImportFunc( mem_v_hDLL, "GlobalReAlloc", "" ) // GlobalReAlloc( hMem, Size, flags )
- ImportFunc( mem_v_hDLL, "GlobalSize", "" ) // GlobalSize( hMem )
- ImportFunc( mem_v_hDLL, "GlobalUnlock", "" ) // GlobalUnlock( hMem )
- ImportFunc( mem_v_hDLL, "RtlFillMemory", "" ) // FillMemory( pDest, Len, Char )
- ImportFunc( mem_v_hDLL, "RtlMoveMemory", "" ) // MoveMemory( pDest, pSrc, Len ) 'Überlappung erlaubt
- ImportFunc( mem_v_hDLL, "RtlZeroMemory", "" ) // ZeroMemory( pDest, Len )
- // EAX, ECX, EDX müssen selbst gerettet werden (da der Windows-Standard diese zu Freiwild erklärt)
- /*
- Inhalt:
- Mem_New - pMem = Mem_New( Size ) - Speicher belegen/reservieren
- Mem_Free - bool = Mem_Free( pMem ) - Speicher freigeben
- Mem_Size - Size = Mem_Size( pMem ) - Größe des belegten Speichers ermitteln
- Mem_Clear - Size = Mem_Clear( pMem ) - Speicher mit Nullen überschreiben
- Mem_Fill - bool = Mem_Fill( pMem, Anz, Fill ) - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
- Mem_Move - bool = Mem_Move( Ziel, Quelle, Anz ) - Speicherinhalte kopieren
- Mem_Resize - pMem = Mem_Resize( pMem, Size ) - Speichergröße ändern/redimensionieren
- */
- ' ********************
- ' Mem_New() - Speicher belegen/reservieren
- ' pMem& = Mem_New( Size& )
- ' Speicher belegen
- ' Reserviert "Size" Bytes Speicherplatz und liefert den Speicherzeiger als Rückgabewert.
- ASM "Mem_New", 1
- PUSH ECX
- MOV ECX, 66 // GMEM_MOVEABLE = 2 | GMEM_ZEROINIT = 64 | GMEM_PTR = 66
- MOV EAX, PAR1 // Size
- CMP EAX, 0 // Null ?
- JZ @@New_Done
- PUSH EAX // Size
- PUSH ECX // Flags
- CALL @GlobalAlloc
- CMP EAX, 0 // Null ?
- JZ @@New_Done
- PUSH EAX // hMem
- CALL @GlobalLock
- @@New_Done:
- POP ECX
- ENDASM
- ' ********************
- ' Mem_Free() - Speicher freigeben
- ' bool% = Mem_Free( pMem& )
- ' Speicher freigeben
- ' Gibt den Speicherbereich auf den der Speicherzeiger zeigt wieder frei.
- ASM "Mem_Free", 1
- PUSH ECX
- MOV EAX, PAR1 // pMem
- CMP EAX, 0
- JZ @@Free_Done
- PUSH EAX // pMem
- CALL @GlobalHandle
- CMP EAX, 0
- JZ @@Free_Error
- MOV ECX, EAX
- PUSH ECX // hMem
- CALL @GlobalUnlock
- CMP EAX, 0
- JZ @@Free_Error
- PUSH ECX // hMem
- CALL @GlobalFree
- CMP EAX, 0
- JNZ @@Free_Done
- @@Free_Error:
- CALL @GetLastError
- @@Free_Done:
- POP ECX
- ENDASM
- ' ********************
- ' Mem_Size() - Größe des belegten Speichers ermitteln
- ' Size& = Mem_Size( pMem& )
- ' Ermittelt die Speichergröße auf die der Speicherzeiger zeigt.
- ' Liefert die Größe des Bereiches zurück.
- ASM "Mem_Size", 1
- PUSH ESI
- PUSH EDI
- XOR EDI,EDI
- MOV ESI, PAR1 // pMem
- CMP ESI, 0
- JZ @@Size_Done
- PUSH ESI // pMem
- CALL @GlobalHandle // --> hMem
- MOV ESI, EAX // hMem
- CMP EAX, 0
- JZ @@Size_Error
- PUSH ESI // hMem
- CALL @GlobalSize // size
- MOV EDI, EAX // size
- JNZ @@Size_Done
- @@Size_Error:
- CALL @GetLastError
- @@Size_Done:
- MOV EAX,EDI
- POP EDI
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Clear() - Speicher mit Nullen überschreiben
- ' Size& = Mem_Clear( pMem& )
- ' Speicher mit Nullen beschreiben
- ' Der angegebene (gesamte) Speicherbereich wird mit binären Nullen überschrieben.
- ' Für eine Teilfüllung ist Mem_Fill() zu nutzen.
- ' benötigt Mem_Size(), "ZeroMemory"
- ' Ergebnis: Größe des überschriebenen Bereiches
- ASM "Mem_Clear", 1
- PUSH ESI
- XOR EAX, EAX
- MOV ESI, PAR1 // pMem
- CMP ESI, 0
- JZ @@Clear_Done
- PUSH ESI // pMem
- CALL @Mem_Size
- CMP EAX, 0 // size
- JZ @@Clear_Done
- PUSH EAX // size
- PUSH ESI // pMem
- CALL @RtlZeroMemory
- @@Clear_Done:
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Fill() - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
- ' bool% = Mem_Fill( pMem&, Anzahl&, FüllChars$ )
- ' belegten Speicher füllen
- ' Ist Anzahl = 0 dann wird Anzahl auf Mem_Size(pMem) gesetzt.
- ' Der angegebene Speicherbereich wird mit Füllzeichen aufgefüllt.
- ' - ohne diese Angabe wird mit Chr$(0) aufgefüllt
- ' - bei einem Zeichen wird sys_FillMemory() genutzt
- ' - bei mehreren Zeichen wird sys_MoveMemory() genutzt
- ASM "Mem_Fill", 3
- PUSH ESI
- PUSH EDI
- PUSH ECX
- PUSH EBX
- PUSH EDX
- MOV ESI, PAR3 // FillChars
- MOV ECX, PAR2 // Anzahl
- MOV EDI, PAR1 // pMem
- MOV EBX, [ESI - 4] // Len(FillChars)
- PUSH EDI // pMem
- CALL @Mem_Size
- CMP ECX, EAX // Anzahl <= Size ?
- JNA @@Fill_Anz_Inside
- MOV ECX, EAX // neue Anzahl
- @@Fill_Anz_Inside:
- CMP ECX, 0 // Anzahl = 0 ?
- JZ @@Fill_Done
- CMP EBX, 1 // FillChars = Null or 1 ? (nein, dann Hauptstück)
- JA @@Fill_more
- // 1 Zeichen
- XOR EDX, EDX // Vorgabe ist Chr$(0)
- CMP ESI, 0 // FillChars = NullString ?
- JZ @@Fill_Start
- MOV DL, [ESI] // Nein, dann FillChar holen
- @@Fill_Start:
- // Bereich mit einem Zeichen füllen
- PUSH EDX // char
- PUSH ECX // Anzahl
- PUSH EDI // pMem
- CALL @RtlFillMemory
- JMP @@Fill_Done
- // --------------------
- @@Fill_more:
- CMP EBX, ECX // LEN( FillChars ) >= Anzahl ?
- JGE @@Fill_MoveOne
- // Da wir den Füllstring mehrmals schreiben wird die Länge benötigt
- PUSH EBX // Len(FillChars)
- // ----------
- @@Fill_Loop:
- CMP ECX, EBX // Anzahl < Len(FillChars)
- JGE @@Fill_Hop // Nein, weiter (sonst den Rest)
- POP EBX // Len(FillChars)
- MOV EBX,ECX // überschreibe mit Rest
- PUSH EBX // Rest
- @@Fill_Hop:
- PUSH EBX // Len(FillChars) (oder Rest)
- PUSH ESI // FillChars
- PUSH EDI // pMem
- CALL @RtlMoveMemory
- POP EBX // Len(FillChars)
- PUSH EBX // Len(FillChars)
- ADD EDI, EBX // pMem + Len(FillChars)
- SUB ECX, EBX // Anzahl - Len(FillChars)
- CMP ECX, 0 // Anzahl > 0
- JA @@Fill_Loop
- // --------------------
- // gesicherten Wert wieder entfernen
- POP EBX // Len(FillChars)
- JMP @@Fill_Done
- @@Fill_MoveOne:
- // Es sind mehr Füllzeichen als der Bereich groß ist.
- // Das läßt sich in einem Rutsch erledigen.
- PUSH ECX // Anzahl
- PUSH ESI // FillChars
- PUSH EDI // pMem
- CALL @RtlMoveMemory
- @@Fill_Done:
- POP EDX
- POP EBX
- POP ECX
- POP EDI
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Move() - Speicherinhalte kopieren
- ' bool = Mem_Move( Ziel&, Quelle&, Anzahl& )
- ' Der angegebene Quellbereich wird in den Zielbereich kopiert.
- ' (Überlappungen von Quelle und Ziel sind hier erlaubt)
- ASM "Mem_Move", 3
- PUSH ESI
- PUSH EDI
- PUSH ECX
- //
- XOR EAX, EAX // 0 = es wurde nichts kopiert
- MOV ECX, PAR3 // Anzahl
- MOV ESI, PAR2 // pQuelle
- MOV EDI, PAR1 // pZiel
- //
- CMP ECX, 0 // Anzahl = 0 ?
- JZ @@Move_Done
- CMP ESI, 0 // Quelle = Null
- JZ @@Move_Done
- CMP EDI, 0 // Ziel = Null
- JZ @@Move_Done
- PUSH ECX // Anzahl
- PUSH ESI // pQuelle
- PUSH EDI // pZiel
- CALL @RtlMoveMemory
- @@Move_Ok:
- INC EAX // 1 = Kopieren wurde durchgeführt
- @@Move_Done:
- POP ECX
- POP EDI
- POP ESI
- ENDASM
- ' ********************
- ' Mem_Resize() - Speichergröße ändern/redimensionieren
- ' pMem& = Mem_Resize( pMem&, Size& )
- ' Speicher redimensionieren
- ' Ändert die Speichergröße auf die der Speicherzeiger zeigt.
- ' Die Größe des angegebenen Speicherbereiches wird auf die neue Größe geändert (wenn ungleich).
- ' Bei einer Vergrößerung des Bereiches bleiben alle Daten erhalten,
- ' bei einer Verkleinerung nur der vordere Teil. (!!!ohne Gewähr!!!)
- ' Liefert den neuen Speicherzeiger zurück.
- ASM "Mem_Resize", 2
- PUSH ECX
- PUSH ESI
- PUSH EDI
- MOV EDI, PAR2 // Size
- MOV ESI, PAR1 // pMem
- CMP ESI, 0 // Nullzeiger ? Dann Mem_New(Size)
- JZ @@Resize_New
- PUSH ESI // pMem
- CALL @GlobalHandle // --> hMem
- CMP ESI, 0
- JZ @@Resize_Error
- MOV ESI, EAX // hMem
- PUSH ESI // hMem
- CALL @GlobalSize // OldSize
- CMP EAX, 0 // Null
- JZ @@Resize_Error
- CMP EAX, EDI // OldSize = Size ? dann keine Größenänderung
- JZ @@Resize_Done
- PUSH ESI // hMem
- CALL @GlobalUnlock
- MOV EAX, 2 // GMEM_MOVEABLE = $2
- PUSH EAX // flags
- PUSH EDI // size
- PUSH ESI // hMem
- CALL @GlobalReAlloc
- MOV ESI, EAX // hMem
- CMP EAX, 0 // Null
- JZ @@Resize_Error
- PUSH ESI // hMem
- CALL @GlobalLock
- MOV ESI, EAX // pMem
- CMP EAX, 0 // Null
- JZ @@Resize_Error
- JMP @@Resize_Done
- @@Resize_New:
- PUSH EDI // Size
- CALL @Mem_New
- MOV ESI, EAX // pMem
- JMP @@Resize_Done
- @@Resize_Error:
- CALL @GetLastError // ohne Parameter
- @@Resize_Done:
- MOV EAX, ESI
- POP EDI
- POP ESI
- POP ECX
- ENDASM
- '$ENDIF
- Cls
- Declare long test1
- Print "Neu"
- test1 = Mem_New( 256 )
- Print "Adresse: "; test1
- Print " Größe: "; Mem_Size(test1)
- Mem_Free(test1)
- WaitInput
- FreeDLL mem_v_hDLL
- End
Programmieren, das spannendste Detektivspiel der Welt. -
Wie kann ich Fehlercodes mitlaufen lassen.
- globale Variable. Wie greife ich darauf zu?
- etwa immer den Zeiger auf die Fehlervariable überall mitschleppen?
- als Objekt programmieren. Keine Ahnung wie in Asm.Programmieren, das spannendste Detektivspiel der Welt. -
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ß
RolandIntel 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.deDieser 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
- // MEM_ASM-Klasse
- CLASS MEM_ASM = #hMem&, \ ' Handle (Adresse) des erzeugten Speichers
- Mem_Asm@, \ ' Konstruktor aMem = New(Mem_Asm, Size) - Speicher belegen/reservieren
- Free@, \ ' Erfolg = aMem.Free( hMem ) - Speicher freigeben
- Size@, \ ' Size = aMem.Size( hMem ) - Größe des belegten Speichers ermitteln
- Clear@, \ ' Size = aMem.Clear( hMem ) - Speicher mit Nullen überschreiben
- Fill@, \ ' Erfolg = aMem.Fill( hMem, Anz, Fill ) - Der angegebene belegte Speicherbereich wird mit Füllzeichen aufgefüllt.
- Move@, \ ' Erfolg = aMem.Move( Ziel, Quelle, Anz ) - Speicherinhalte kopieren
- Resize@, \ ' Erfolg = aMem.Resize( hMem, Size ) - Speichergröße ändern/redimensionieren
- getHandle@ ' hMem = aMem.GetHandle () - Handle ermitteln
- Declare handle MEM_ASM.hDLL ' Klassenvariable
- Proc MEM_ASM.Mem_Asm // Konstruktor
- /***********************/
- Parameters long size
- 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
- If fAddr("Mem_New") = 0 // Der Code bis zum zugehörigen ENDIF wird nur beim allerersten Mal aufgerufen. Dann stehen die importierten Funktionen
- // und die mit ASM hinzugefügten Funktionen zur Verfügung
- ImportFunc( MEM_ASM.hDLL, "GetLastError", "" ) // GetLastError( )
- ImportFunc( MEM_ASM.hDLL, "GlobalAlloc", "" ) // GlobalAlloc( flags, Size )
- ImportFunc( MEM_ASM.hDLL, "GlobalFree", "" ) // GlobalFree( hMem )
- ImportFunc( MEM_ASM.hDLL, "GlobalHandle", "" ) // GlobalHandle( pMem )
- ImportFunc( MEM_ASM.hDLL, "GlobalLock", "" ) // GlobalLock( hMem )
- ImportFunc( MEM_ASM.hDLL, "GlobalReAlloc", "" ) // GlobalReAlloc( hMem, Size, flags )
- ImportFunc( MEM_ASM.hDLL, "GlobalSize", "" ) // GlobalSize( hMem )
- ImportFunc( MEM_ASM.hDLL, "GlobalUnlock", "" ) // GlobalUnlock( hMem )
- ImportFunc( MEM_ASM.hDLL, "RtlFillMemory", "" ) // FillMemory( pDest, Len, Char )
- ImportFunc( MEM_ASM.hDLL, "RtlMoveMemory", "" ) // MoveMemory( pDest, pSrc, Len ) 'Überlappung erlaubt
- ImportFunc( MEM_ASM.hDLL, "RtlZeroMemory", "" ) // ZeroMemory( pDest, Len )
- ASM "Mem_New", 1
- PUSH ECX
- MOV ECX, 66 // GMEM_MOVEABLE = 2 | GMEM_ZEROINIT = 64 | GMEM_PTR = 66
- MOV EAX, PAR1 // Size
- CMP EAX, 0 // Null ?
- JZ @@New_Done
- PUSH EAX // Size
- PUSH ECX // Flags
- CALL @GlobalAlloc
- CMP EAX, 0 // Null ?
- JZ @@New_Done
- PUSH EAX // hMem
- CALL @GlobalLock
- @@New_Done:
- POP ECX
- ENDASM
- ASM "Mem_Free", 1
- PUSH ECX
- MOV EAX, PAR1 // pMem
- CMP EAX, 0
- JZ @@Free_Done
- PUSH EAX // pMem
- CALL @GlobalHandle
- CMP EAX, 0
- JZ @@Free_Error
- MOV ECX, EAX
- PUSH ECX // hMem
- CALL @GlobalUnlock
- CMP EAX, 0
- JZ @@Free_Error
- PUSH ECX // hMem
- CALL @GlobalFree
- CMP EAX, 0
- JNZ @@Free_Done
- @@Free_Error:
- CALL @GetLastError
- @@Free_Done:
- POP ECX
- ENDASM
- ASM "Mem_Size", 1
- PUSH ESI
- PUSH EDI
- XOR EDI,EDI
- MOV ESI, PAR1 // pMem
- CMP ESI, 0
- JZ @@Size_Done
- PUSH ESI // pMem
- CALL @GlobalHandle // --> hMem
- MOV ESI, EAX // hMem
- CMP EAX, 0
- JZ @@Size_Error
- PUSH ESI // hMem
- CALL @GlobalSize // size
- MOV EDI, EAX // size
- JNZ @@Size_Done
- @@Size_Error:
- CALL @GetLastError
- @@Size_Done:
- MOV EAX,EDI
- POP EDI
- POP ESI
- ENDASM
- ASM "Mem_Clear", 1
- PUSH ESI
- XOR EAX, EAX
- MOV ESI, PAR1 // pMem
- CMP ESI, 0
- JZ @@Clear_Done
- PUSH ESI // pMem
- CALL @Mem_Size
- CMP EAX, 0 // size
- JZ @@Clear_Done
- PUSH EAX // size
- PUSH ESI // pMem
- CALL @RtlZeroMemory
- @@Clear_Done:
- POP ESI
- ENDASM
- ASM "Mem_Fill", 3
- PUSH ESI
- PUSH EDI
- PUSH ECX
- PUSH EBX
- PUSH EDX
- MOV ESI, PAR3 // FillChars
- MOV ECX, PAR2 // Anzahl
- MOV EDI, PAR1 // pMem
- MOV EBX, [ESI - 4] // Len(FillChars)
- PUSH EDI // pMem
- CALL @Mem_Size
- CMP ECX, EAX // Anzahl <= Size ?
- JNA @@Fill_Anz_Inside
- MOV ECX, EAX // neue Anzahl
- @@Fill_Anz_Inside:
- CMP ECX, 0 // Anzahl = 0 ?
- JZ @@Fill_Done
- CMP EBX, 1 // FillChars = Null or 1 ? (nein, dann Hauptstück)
- JA @@Fill_more
- // 1 Zeichen
- XOR EDX, EDX // Vorgabe ist Chr$(0)
- CMP ESI, 0 // FillChars = NullString ?
- JZ @@Fill_Start
- MOV DL, [ESI] // Nein, dann FillChar holen
- @@Fill_Start:
- // Bereich mit einem Zeichen füllen
- PUSH EDX // char
- PUSH ECX // Anzahl
- PUSH EDI // pMem
- CALL @RtlFillMemory
- JMP @@Fill_Done
- // --------------------
- @@Fill_more:
- CMP EBX, ECX // LEN( FillChars ) >= Anzahl ?
- JGE @@Fill_MoveOne
- // Da wir den Füllstring mehrmals schreiben wird die Länge benötigt
- PUSH EBX // Len(FillChars)
- // ----------
- @@Fill_Loop:
- CMP ECX, EBX // Anzahl < Len(FillChars)
- JGE @@Fill_Hop // Nein, weiter (sonst den Rest)
- POP EBX // Len(FillChars)
- MOV EBX,ECX // überschreibe mit Rest
- PUSH EBX // Rest
- @@Fill_Hop:
- PUSH EBX // Len(FillChars) (oder Rest)
- PUSH ESI // FillChars
- PUSH EDI // pMem
- CALL @RtlMoveMemory
- POP EBX // Len(FillChars)
- PUSH EBX // Len(FillChars)
- ADD EDI, EBX // pMem + Len(FillChars)
- SUB ECX, EBX // Anzahl - Len(FillChars)
- CMP ECX, 0 // Anzahl > 0
- JA @@Fill_Loop
- // --------------------
- // gesicherten Wert wieder entfernen
- POP EBX // Len(FillChars)
- JMP @@Fill_Done
- @@Fill_MoveOne:
- // Es sind mehr Füllzeichen als der Bereich groß ist.
- // Das läßt sich in einem Rutsch erledigen.
- PUSH ECX // Anzahl
- PUSH ESI // FillChars
- PUSH EDI // pMem
- CALL @RtlMoveMemory
- @@Fill_Done:
- POP EDX
- POP EBX
- POP ECX
- POP EDI
- POP ESI
- ENDASM
- ASM "Mem_Move", 3
- PUSH ESI
- PUSH EDI
- PUSH ECX
- //
- XOR EAX, EAX // 0 = es wurde nichts kopiert
- MOV ECX, PAR3 // Anzahl
- MOV ESI, PAR2 // pQuelle
- MOV EDI, PAR1 // pZiel
- //
- CMP ECX, 0 // Anzahl = 0 ?
- JZ @@Move_Done
- CMP ESI, 0 // Quelle = Null
- JZ @@Move_Done
- CMP EDI, 0 // Ziel = Null
- JZ @@Move_Done
- PUSH ECX // Anzahl
- PUSH ESI // pQuelle
- PUSH EDI // pZiel
- CALL @RtlMoveMemory
- @@Move_Ok:
- INC EAX // 1 = Kopieren wurde durchgeführt
- @@Move_Done:
- POP ECX
- POP EDI
- POP ESI
- ENDASM
- ASM "Mem_Resize", 2
- PUSH ECX
- PUSH ESI
- PUSH EDI
- MOV EDI, PAR2 // Size
- MOV ESI, PAR1 // pMem
- CMP ESI, 0 // Nullzeiger ? Dann Mem_New(Size)
- JZ @@Resize_New
- PUSH ESI // pMem
- CALL @GlobalHandle // --> hMem
- CMP ESI, 0
- JZ @@Resize_Error
- MOV ESI, EAX // hMem
- PUSH ESI // hMem
- CALL @GlobalSize // OldSize
- CMP EAX, 0 // Null
- JZ @@Resize_Error
- CMP EAX, EDI // OldSize = Size ? dann keine Größenänderung
- JZ @@Resize_Done
- PUSH ESI // hMem
- CALL @GlobalUnlock
- MOV EAX, 2 // GMEM_MOVEABLE = $2
- PUSH EAX // flags
- PUSH EDI // size
- PUSH ESI // hMem
- CALL @GlobalReAlloc
- MOV ESI, EAX // hMem
- CMP EAX, 0 // Null
- JZ @@Resize_Error
- PUSH ESI // hMem
- CALL @GlobalLock
- MOV ESI, EAX // pMem
- CMP EAX, 0 // Null
- JZ @@Resize_Error
- JMP @@Resize_Done
- @@Resize_New:
- PUSH EDI // Size
- CALL @Mem_New
- MOV ESI, EAX // pMem
- JMP @@Resize_Done
- @@Resize_Error:
- CALL @GetLastError // ohne Parameter
- @@Resize_Done:
- MOV EAX, ESI
- POP EDI
- POP ESI
- POP ECX
- ENDASM
- EndIf
- .hMem& = Mem_New(size)
- var int Ergebnis = 0
- if .hMem& > 0
- Ergebnis = 1
- EndIf
- EndProc
- Proc MEM_ASM.Free
- /***************/
- Var int Ergebnis = Mem_Free(.hMem&)
- FreeDLL MEM_ASM.hDLL
- Return Ergebnis
- EndProc
- Proc MEM_ASM.Size
- /***************/
- Return Mem_Size(.hMem&)
- EndProc
- Proc MEM_ASM.Clear
- /****************/
- Return Mem_Clear(.hMem&)
- EndProc
- Proc MEM_ASM.Fill
- /***************/
- Parameters long Anz, cFill
- Return Mem_Fill(.hMem&, Anz, cFill)
- EndProc
- Proc MEM_ASM.Move
- /***************/
- Parameters long ziel, Quelle, Anz
- Return Mem_Move(Ziel, Quelle, Anz)
- EndProc
- Proc MEM_ASM.Resize
- /*****************/
- parameters long size
- var int ergebnis = 0
- If Mem_Resize(.hMem&, Size)
- ergebnis = 1
- endif
- return ergebnis
- EndProc
- Proc MEM_ASM.getHandle
- /********************/
- Return .hMem&
- EndProc
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:
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)
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
- Declare Mem Quelle, Ziel
- Declare String Datei
- Declare Handle hFile
- Declare Int DateiLaenge, ZLaenge, Zeilen, ZielGross, Gelesen
- ASM "Hexe", 5
- push ebx
- push ecx
- push edx
- push edi
- push esi
- mov esi, Par1 // Parameter 1: Quellbereich
- mov edi, Par2 // Parameter 2: Zielbereich
- mov ecx, Par3 // Parameter 3: QuellLänge
- mov edx, Par4 // Parameter 4: AusgabeLänge (Zeilenlänge üblicherweise 16 oder mitunter
- auch 8)
- mov eax, Par5 // Parameter 5: Anzeigeadresse der ersten Zeile
- mov [@@Adresse], eax
- mov [@@ZLang], edx
- // wenn als Zielbereich 0 gesetzt wird, wird nichts ausgeführt und anhand der QuellLänge
- // und AusgabeLänge wird die notwendige Mindestgröße für den Zielbereich berechnet und
- zurückgegeben
- or edi, edi
- jz @@MC
- jmp @@Begin
- // ein direkter Sprung JNZ @@SizeCalc ist zu lang
- // ebenso wie die Umkehrung JNZ @@Begin
- // deshalb dieser relative Sprung über einen JMP
- @@MC:
- jmp @@SizeCalc
- @@Zeile:
- dd 0
- @@ZLang:
- dd 0
- @@Adresse:
- dd 0
- @@AsciiZeile: // gibt die Eingabe als Text aus und ersetzt besondere Zeichen durch einen
- Mittelpunkt
- mov esi, [@@Zeile]
- @@AsciiByte:
- lodsb
- cmp al, $5e
- jz @@NoChar
- cmp al, $60
- jz @@NoChar
- cmp al, $a8
- jz @@NoChar
- cmp al, $b4
- jz @@NoChar
- cmp al, 31
- jg @@AsciiOut
- @@NoChar:
- mov al, $b7
- @@AsciiOut:
- stosb
- dec edx
- jnz @@AsciiByte
- ret
- @@Conv: // Konvertiert ein Nibble
- and al, $0f
- add al, $30
- cmp al, $3a
- jl @@NibOk
- add al, 7
- @@NibOk:
- ret
- @@ConvByte: // Konvertiert ein Byte
- push eax
- shr al, 4
- call @@Conv
- stosb
- pop eax
- call @@Conv
- stosb
- ret
- @@LongConv: // Konvertiert einen Long
- mov al, [esi + 3]
- call @@ConvByte
- mov al, [esi + 2]
- call @@ConvByte
- mov al, [esi + 1]
- call @@ConvByte
- mov al, [esi]
- call @@ConvByte
- ret
- @@AdrOut: // Gibt die Adresse hexadezimal zu 8 Zeichen Länge aus
- push esi
- mov esi, @@Adresse
- @@NextAdr:
- call @@LongConv
- mov al, 32
- stosb
- stosb
- mov eax, [@@Adresse]
- add eax, edx
- mov [@@Adresse], eax
- pop esi
- ret
- @@Begin:
- cld
- mov [@@Zeile], esi // notiert aktuellen Zeilenbeginn in der Quelle
- call @@AdrOut // Quelladresse ausgeben
- @@Zeichen:
- lodsb
- call @@ConvByte
- mov al, 32
- stosb
- dec edx
- jnz @@InZeile // in aktueller Zeile verbleiben
- // oder Zeilenschaltung einfügen
- mov edx, [@@ZLang]
- call @@AsciiZeile // hier ASCII-Interpretation
- mov al, 13
- stosb
- mov al, 10
- stosb
- mov edx, [@@ZLang]
- mov [@@Zeile], esi // notiert neuen Zeilenbeginn in der Quelle
- call @@AdrOut // Quelladresse für neue Zeile ausgeben
- @@InZeile:
- dec ecx
- jnz @@Zeichen // Ausgabelänge noch nicht erreicht
- // Restlänge der letzten Zeile steht in EDX
- or edx, edx
- jz @@NoRest
- push edx
- mov al, 32
- @@RestFill:
- stosb
- stosb
- stosb
- dec edx
- jnz @@RestFill
- pop edx
- mov eax, [@@ZLang]
- cmp eax, edx
- jz @@NoRest
- sub eax, edx
- mov edx, eax
- call @@AsciiZeile
- @@NoRest:
- mov al, 13
- stosb
- mov al, 10
- stosb
- xor eax, eax
- stosb
- jmp @@Raus
- @@SizeCalc: // Berechne Speichergröße für Ausgabe
- push edx
- mov eax, ecx
- mov ecx, edx
- xor edx, edx
- idiv ecx
- inc eax // Anzahl Zeilen
- mov ecx, eax // Anzahl Zeilen nach ECX
- pop eax // Zeilenlänge
- add eax, eax
- add eax, eax
- add eax, 12
- mul ecx
- add eax, 4
- @@Raus:
- pop esi
- pop edi
- pop edx
- pop ecx
- pop ebx
- EndASM
- CLS
- ZLaenge = 16
- Datei = LoadFile$("Datei wählen", "C:\*.*")
- If Datei <> ""
- hFile = Assign(Datei)
- OpenRW hFile
- Dateilaenge = GetFileSize(hFile)
- DIM Quelle, DateiLaenge
- ZielGross = Hexe(Quelle, 0, DateiLaenge, ZLaenge, 0) ' Zielspeichergröße berechnen lassen und
- dimmen
- DIM Ziel, ZielGross
- Gelesen = BlockRead(hFile, Quelle, 0, DateiLaenge)
- Close hFile
- Hexe(Quelle, Ziel, DateiLaenge, ZLaenge, 0) ' Hexdump erzeugen
- Move("MemToList", Ziel, "\n")
- ListBox$("Hexdump", 2)
- Dispose Quelle, Ziel
- EndIf
- Print "Fertig"
- WaitInput
- End
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ß VolkmarDieser Beitrag wurde bereits 2 mal editiert, zuletzt von Volkmar ()
-
-
Teilen
- Facebook 0
- Twitter 0
- Google Plus 0
- Reddit 0