;--------------------- Setzen Alignment, K.Helbing ("Helle"), PureBasic 4.00 Beta 10, 14.04.2006 ------------------- ;- Alignment: Das Legen von CPU-Instruktionen (und auch Daten!) auf Speicheradressen, die ohne Rest durch 4 teilbar ;- sind (oder anderer Wert, der eine Zweier-Potenz sein muss; bei einem 32-Bit Betriebssystem aber sinnvollerweise ;- 4). Auf diese Speicheradressen kann effektiver zugegriffen werden als auf "ungerade", das Programm sollte also ;- schneller werden. Dies zeigt sich messbar natürlich nur bei etwas größeren Anwendungen (EXE!); ein Zehnzeiler in ;- einer (fast) Endlos-Schleife als Test ist Nonsens. Ein Schachprogramm lief ca.7-8% schneller. ;- Da es Unfug ist, jede CPU-Instruktion zu "alignmentieren", wurden in Programmen häufig vorkommende Instruktionen ;- ausgewählt, die 4-oder 8-Byte langen OP-Code haben. ;- Es besteht natürlich immer die "Gefahr", dass eigentlich gut liegende Befehle durch an anderer Stelle eingeschobene ;- NOP´s auf schlechtere "Plätze" verschoben werden. Dann ist eben der Gewinn geringer bzw. garnicht da. Probieren! ;- Gesetzt wird Alignment immer nach - JMP ;- - RET ;- vor - CMP WORD[MEM],WERT bei WERT <80h ist 8-Byte-Opcode ;- - CMP [16-Bit-REG],WERT ist 4-Byte-Opcode für Wert<80h ;- - MOV " " " ;- - ADD " " " ;- - SUB " " " für Wert<80h wenn nicht AX-Register ;- - ADC " " " ;- - SBB " " " ;- - AND " " " ;- - SHL " " " für Wert >1 ;- - SHR " " " " ;- - LEA in Verbindung mit [ESP+...]" Alle ausser ESP+0 ;- - PUSH " " " ;- - INC " " " ;- - DEC " " " ;- - FADD " " " ;- - FLD " " " ;- Die Anzahl der max. zulässigen NOP´s hintereinander kann ausgewählt werden (1 bis 3). Je nach Programm kann die ;- eine oder andere Auswahl die besten Ergebnisse liefern (einfach ausprobieren!). ;- Erweiterungen bezüglich der Opcode-Auswahl sind jederzeit möglich. ;- Die EXE-Datei wird (natürlich) um die Anzahl der eingefügten NOP´s grösser (aber nicht direkt vergleichbar, ;- weil PB einige generelle Aligments setzt). ;- Je nach Datei-Grösse und PC kann der Durchlauf durchaus einige Minuten dauern. ;- Im EXE-Namen ist als Ziffer die Anzahl der vorher ausgewählten max.zulässigen NOP´s hintereinander angegeben. ;- Empfehlung: Das Ganze in einer RAM-Disk ablaufen lassen (auch wegen der vielen HD-Zugriffe, aber keine Angst!). ;- Als "Wiederfinder" in der EXE-Datei wird der Befehl UD2 verwendet, den ja wohl keiner in seinem Programm ;- verwendet ;). Eine Version, dies flexibler zu gestalten, ist in Arbeit. ;- WICHTIG! AliSet und die eigene Quelldatei ins Compilers-Verzeichnis von PB kopieren! ;- Quell- oder sonstige PB-Dateien werden nicht verändert; überschrieben wird nur die evtl. vorhandene EXE-Datei. Global FILELAENGEA.l = $0 ;Filelänge ASM-Datei Global FILELAENGEE.l = $0 ;Filelänge EXE-Datei Global FILELAENGEA1.l = $0 Global RAMSPEICHER.l = $0 ;erforderliche RAM-Grösse Global STARTTIME.l = $0 Global ENDTIME.l = $0 Global GESTIME.l = $0 Global ENDE.l = $0 Global NOPPI.l = $1 ;Anzahl der zulässigen NOP´s hintereinander Global NOPPI1.l = $0 Global NOPPI2.l = $0 Global NOPPI3.l = $0 Global DURCHLAUF.l = $0 Global S1.l = $47494c41 ;ALIG Global S2.l = $0a34204e ;N 4 mit LF Global S3.l = $0a324455 ;UD2 mit LF Global M1.l = $564f4d ;MOV Leerzeichen werden unten auf Null gesetzt! Global M2.l = $44524f57 ;WORD Global M3.l = $504d43 ;CMP Global M4.l = $434e49 ;INC Global M5.l = $434544 ;DEC Global M6.l = $434441 ;ADC Global M7.l = $424253 ;SBB Global M8.l = $504d4a ;JMP Global M9.l = $0a544552 ;RET Global M10.l = $444441 ;ADD Global M11.l = $4c4853 ;SHL Global M12.l = $524853 ;SHR Global M13.l = $425553 ;SUB Global M14.l = $0b505345 ;ESP+ Global M15.l = $41454c ;LEA Global M16.l = $48535550 ;PUSH Global M17.l = $444e41 ;AND Global M18.l = $44444146 ;FADD Global M19.l = $444c46 ;FLD Global M20.l = $61746164 ;data Global INSTR.l = $0 Global WT.b = $0 Global WT1.b = $0 Global STUFE.b = $0 Global *MemoryID.l = $0 Global PROGID.l = $0 Global FINDWERT.w = $0 Global PROG$ = "" Global GESTIME$ = "" ;-------- Abfrage Name der Quell-Datei PROG$ = InputRequester("PB-Quelldatei","Bitte Quelldatei ohne Erweiterung (.PB) eingeben!","") ;-------- Test, ob Dateiname gültig ist If ReadFile(1,PROG$ + ".PB") ElseIf MessageRequester("Status", "Datei nicht gefunden!") End CloseFile(1) EndIf ;-------- Abfrage, wieviel NOP´s hintereinander zulässig sein sollen (NOPPI setzen) If OpenWindow(0, 0, 0, 260, 130, "Welche Version(en) soll(en) erstellt werden?", #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) CheckBoxGadget(1, 10, 10, 75, 20, "Max.1 NOP") CheckBoxGadget(2, 10, 40, 85, 20, "Max.2 NOP´s") CheckBoxGadget(3, 10, 70, 85, 20, "Max.3 NOP´s") ButtonGadget(4, 10, 100, 240, 20, "O.K.") Repeat WaitWindowEvent() ENDE = EventGadget() NOPPI1 = GetGadgetState(1) NOPPI2 = GetGadgetState(2) NOPPI3 = GetGadgetState(3) Until ENDE = 4 And (NOPPI1 <> 0 Or NOPPI2 <> 0 Or NOPPI3 <> 0) DURCHLAUF = NOPPI1 + NOPPI2 + NOPPI3 EndIf CloseWindow(0) ;-------- erstmal die ASM-Datei zur Bearbeitung erstellen ("commented"), "exe" damit Programm nicht ;-------- startet sondern nur EXE-Datei erstellt wird. "0" wie Null für keine NOP´s. MessageRequester("Status", "Nach der OK-Bestätigung bitte warten bis Fertigmeldung erscheint!") PROGID = RunProgram("PBCompiler.exe", PROG$ + ".pb /inlineasm /quiet /commented /exe " + PROG$ + "0.exe", "",#PB_Program_Hide | #PB_Program_Open) WaitProgram(PROGID) CloseProgram(PROGID) ;-------- Test, ob PureBasic.asm erstellt werden konnte If ReadFile(1,"PureBasic.asm") ElseIf MessageRequester("Status", "Konnte PureBasic.asm nicht erstellen! (Festplatte voll?") End CloseFile(1) EndIf OpenFile(1,"PureBasic.asm") FILELAENGEA = Lof(1) ;hier für Ermittlung RAM-Reservierung; Lof geht nicht bei ReadFile! CloseFile(1) ;-------- Test, ob die "Original"-exe erstellt werden konnte If ReadFile(2,PROG$ + "0.exe") ElseIf MessageRequester("Status", "Konnte die 'Original'-exe nicht erstellen! (Festplatte voll?)") End CloseFile(2) EndIf ;-------- Test auf Byte-Folge 0f0bh, dem Opcode für UD2. Falls vorhanden erstmal Ende s.weiter unten! OpenFile(2,PROG$ + "0.exe") FILELAENGEE = Lof(2) ;hier für Ermittlung RAM-Reservierung; Lof geht nicht bei ReadFile! While Eof(2) = $0 ;Original-exe Byte-weise einlesen und auf evtl. schon vorhandenen If ReadByte(2) = $0f ; Opcode von UD2 testen, könnte aber auch blöderweise ein Datum sein If ReadByte(2) = $0b MessageRequester("Status", "Opcode von UD2 gefunden; wir lassen´s erstmal!") End ;MOV FINDWERT,1h EndIf EndIf Wend CloseFile(2) ;-------- Benötigten RAM-Speicher abschätzen If FILELAENGEA >= FILELAENGEE RAMSPEICHER = FILELAENGEA ElseIf RAMSPEICHER = FILELAENGEE EndIf RAMSPEICHER = 3 * RAMSPEICHER CMP RAMSPEICHER,20000h ;128kB sollens schon sein, 64 davon für Trenner-Test JAE l_ramgenug MOV RAMSPEICHER,20000h ;-------- RAM-Speicher für direkten Zugriff reservieren RAMGENUG: *MemoryID = AllocateMemory(RAMSPEICHER) If *MemoryID = $0 MessageRequester("Fehler!", "Konnte den benötigten Speicher nicht reservieren!") End EndIf RAMSPEICHER = RAMSPEICHER / 2 ;erste Hälfte für asm, zweite für exe ;MOV FINDWERT,1h ;für Test CMP FINDWERT,0h JE l_aufgehts ;keine Klimmzüge notwendig ;-------- Test auf Word-Folge für Finder-Test OpenFile(2,PROG$ + "0.exe") ReadFile(2,PROG$ + "0.exe") ReadData(2,*MemoryID+RAMSPEICHER,FILELAENGEE) CloseFile(2) MOV esi,*MemoryID MOV eax,esi ADD esi,RAMSPEICHER ;Beginn EXE MOV ecx,FILELAENGEE XOR ebx,ebx MOV dl,1h FTEST: MOV bx,[esi] MOV [eax+ebx],dl INC esi SUB ecx,1h JNC l_ftest MOV esi,*MemoryID MOV ebx,0ffffh FTEST1: TEST [esi+ebx],dl JZ l_ftreffer SUB ebx,1h JNC l_ftest1 MessageRequester("Abbruch!", "Konnte für meine Methode kein geeignetes Finder-Word finden!") End FTREFFER: MOV FINDWERT,bx MessageRequester("Wert gefunden!", StrU(FINDWERT,#Word)) ;-------- Auf geht´s, der Stress beginnt... AUFGEHTS: STARTTIME = ElapsedMilliseconds() CopyFile("PureBasic.asm","OldPureBasic.asm") ;für Testzwecke, kann entfallen MOV esi,*MemoryID ;ESI ist damit tabu! XOR edi,edi ;-------- zur Beschleunigung die Kommentare entfernen OpenFile(1,"PureBasic.asm") While Eof(1) = 0 ReadByte(1) ;eingelesenes Byte in AL CMP STUFE,0h ;STUFE=0 ist Suche nach Doppelpunkt mit Leerzeichen davor JNE l_pre1 CMP al,3ah ;":" JNE l_pre3 CMP byte[esi-1h+edi],20h JNE l_pre3 ;bis zum Doppelpunkt mit Leerzeichen davor komplett schreiben MOV STUFE,1h JMP l_pre3 PRE1: CMP al,3bh ;";" JNE l_pre2 CMP WT,0ah ;ist das zuletzt geschriebene Byte JNE l_pre3 MOV STUFE,2h JMP l_pre4 PRE2: CMP STUFE,2h JNE l_pre3 CMP al,0ah ;LF JNE l_pre4 MOV STUFE,1h JMP l_pre4 PRE3: MOV [esi+edi],al INC edi MOV WT,al PRE4: Wend CloseFile(1) DEC edi MOV FILELAENGEA,edi MOV FILELAENGEA1,edi ;für weitere Durchläufe DeleteFile("PureBasic.asm") OpenFile(1,"PureBasic.asm") WriteData(1,*MemoryID,FILELAENGEA) CloseFile(1) CopyFile("PureBasic.asm","OldPureBasic1.asm") CMP NOPPI3,0h JNE l_nopset3 CMP NOPPI2,0h JNE l_nopset2 JMP l_nopset1 NOPSET3: INC NOPPI NOPSET2: INC NOPPI NOPSET1: ;-------- eigentliche Prozedur SEARCH0: XOR bp,bp ;Merker ob ALIGN "gut" ist MOV ebx,1h ;evtl. Test auf "Main" o.ä. für grösseren Wert, ist aber nicht relevant MOV edx,0dfdfdfdfh SEARCH: MOV al,[esi+ebx-1h] CMP al,3bh ;";" JE l_nofound4 CMP al,41h ;wegen z.B. PAND, FIADD und ähnlichen möglichen Fehlinterpretationen JAE l_nofound1 MOV eax,[esi+ebx] CMP eax,M20 ;"data" JE l_fertig AND eax,edx ;Kleinbuchstaben-Bit löschen, Leerzeichen wird Null! MOV edi,ebx ;ist die eventuelle Einfüge-Stelle MOV INSTR,eax ;für z.B. Test ob WORD CMP eax,M18 ;FADD für Float-Instruktionen mal 66h anstelle 90h testen! JE l_voradd3 ;Test auf esp+ CMP eax,M19 ;FLD JE l_voradd3 CMP eax,M8 ;JMP JE l_nachjmp CMP eax,M9 ;RET JE l_nachjmp CMP eax,M3 ;CMP JE l_vorcmp CMP eax,M10 ;ADD JE l_vorcmp ;JE l_voradd ;mögliche Variationen, um Ergebnis evtl. zu verbessern (auch komplettes ; Weglassen von Abfragen möglich) CMP eax,M1 ;MOV JE l_voradd CMP eax,M11 ;SHL JE l_vorshift CMP eax,M12 ;SHR JE l_vorshift CMP eax,M13 ;SUB JE l_vorcmp ;JE l_voradd CMP eax,M6 ;ADC ;JE l_vorcmp JE l_voradd CMP eax,M7 ;SBB ;JE l_vorcmp JE l_voradd CMP eax,M15 ;LEA JE l_voradd3 CMP eax,M16 ;PUSH JE l_voradd3 CMP eax,M4 ;INC JE l_voradd3 CMP eax,M5 ;DEC JE l_voradd3 CMP eax,M17 ;AND JE l_vorcmp ;JE l_voradd JMP l_nofound1 ;-------- Align NACH einem JMP oder RET einfügen NACHJMP: INC ebx CMP byte[esi+ebx],0ah ;Ende der Zeile? JNE l_nachjmp ;nein INC ebx MOV edi,ebx ;Einfügestelle INC bp ;Merker für "gutes" ALIGN JMP l_found ;-------- Align VOR div.Instruktionen bei bestimmten Konstellationen VORCMP: CALL l_wordtest XOR ecx,ecx ;für Werttest CMP WT,cl ;Null? JE l_voradd2 ;kein Word, nächster Test ;-------- ist WORD NOKLAMMER: INC ebx MOV al,[esi+ebx] CMP al,5bh ;[ JNE l_noklammer NOKLAMMER1: INC ebx MOV al,[esi+ebx] CMP al,20h JE l_noklammer1 ;Leerzeichen CMP al,5fh ;_ als Kennung für Variable JE l_werttest CMP al,5dh ;] JE l_nofound1 JMP l_noklammer1 WERTTEST: INC ebx MOV al,[esi+ebx] CMP al,2ch ;Komma JNE l_werttest WERTTEST1: INC ebx MOV al,[esi+ebx] WERTTEST3: CMP al,30h ;Leerzeichen oder führende Nullen JBE l_werttest1 WERTTEST2: CMP al,0ah JE l_auswertungd CMP al,68h ;h JE l_auswertungh CMP al,48h ;H JE l_auswertungh CMP al,20h JE l_werttest4 ;für dez bis Zeilenende SHL ecx,8h MOV cl,al WERTTEST4: INC ebx MOV al,[esi+ebx] JMP l_werttest2 AUSWERTUNGH: TEST ecx,0ffff0000h JNZ l_nofound1 CMP ch,38h JAE l_nofound1 JB l_found AUSWERTUNGD: TEST ecx,0ff000000h JNZ l_nofound1 CMP ch,39h JA l_nofound1 ;Register MOV eax,ecx SHR eax,8h CMP ah,31h JA l_nofound1 JB l_found CMP ch,32h JA l_nofound1 JB l_found CMP cl,38h JAE l_nofound1 JMP l_found ;-------- Ende Werttest VORADD: ADD ebx,3h VORADD1: INC ebx VORADD2: MOV al,[esi+ebx] CMP al,5bh ; [ JE l_nofound3 AND al,dl JZ l_voradd1 MOV WT,al INC ebx MOV al,[esi+ebx] ;Test auf 2.Buchstaben CMP al,5fh ;_ Variablen aussieben JE l_nofound1 AND al,dl MOV WT1,al CMP al,58h ;X? für AX.BX,CX,DX JE l_isregister CMP al,49h ;I? für DI,SI JE l_isregister CMP al,50h ;P? für BP JE l_isregister ;-------- Suche nach ESP+Wert, Wert>0 VORADD3: INC ebx MOV eax,[esi+ebx] CMP al,0ah JE l_nofound1 AND eax,edx CMP eax,M14 ;ESP+? JNE l_voradd3 ADD ebx,3h VORADD4: INC ebx MOV al,[esi+ebx] CMP al,5dh ;] JE l_nofound1 CMP al,31h JAE l_found ;grösser Null JMP l_voradd4 ISREGISTER: INC ebx MOV al,[esi+ebx] CMP al,30h ;Leerzeichen, Komma, Null JB l_isregister JE l_isregister1 CMP al,39h JA l_nofound1 ISREGISTER1: MOV ecx,INSTR CMP ecx,M1 ;MOV? JE l_found ;kein Werttest CMP WT,41h JE l_found ;ist AX-Register DX??? ;CMP WT,44h ;nochmal in Ruhe anschauen, ob lohnend ;JNE l_isregister3 ;CMP WT1,58h ;JE l_found ISREGISTER3: XOR ecx,ecx JMP l_werttest3 VORSHIFT: CALL l_wordtest CMP WT,1h JNE l_vorshift2 ADD ebx,3h JMP l_found VORSHIFT1: INC ebx VORSHIFT2: MOV al,[esi+ebx] CMP al,5fh ;_ Variablen aussieben Klammer? Sollte hier egal sein JE l_nofound1 AND al,dl JZ l_vorshift1 INC ebx MOV al,[esi+ebx] ;Test auf 2.Buchstaben AND al,dl CMP al,58h ;X? für AX.BX,CX,DX JE l_isregister2 CMP al,49h ;I? für DI,SI JE l_isregister2 CMP al,50h ;P? für BP JNE l_nofound1 ISREGISTER2: INC ebx MOV al,[esi+ebx] CMP al,2ch ;Leerzeichen, Komma JBE l_isregister2 INC ebx CMP al,31h JE l_nofound1 ;1-er Shifts haben eigenen Opcode! CMP al,39h ;Test nicht für Wert, sondern auf Register! JA l_nofound1 ;-------- was lohnenswertes (hoffentlich!) gefunden FOUND: ADD FILELAENGEA,8h ;für 1x ALIGN wird die Datei 8 Byte länger INC ebx ; ADD ebx,6h ;-------- Restdatei nach "hinten" verschieben MOV ecx,FILELAENGEA SUB ecx,4h SCHIEBEN1: MOV eax,dword[esi-8h+ecx] MOV dword[esi+ecx],eax SUB ecx,4h CMP ecx,edi JAE l_schieben1 ;-------- "ALIGN 4" einfügen mit LF MOV eax,S1 MOV [esi+edi],eax MOV eax,S2 MOV dword[esi+4h+edi],eax OR bp,bp JNE l_genehm CMP NOPPI,3h JE l_genehm ;3 NOPS´s zulässig ;-------- Klimmzug mit UD2 (oder Finder -Word) notwendig PUSH edi ;Einfügestelle von ALIGN 4 merken NACHALI: INC ebx CMP byte[esi+ebx],0ah ;Ende der Zeile? JNE l_nachali ;nein INC ebx MOV edi,ebx ;Einfügestelle für UD2 ADD FILELAENGEA,4h ;für 1x UD2 wird die Datei 4 Byte länger INC ebx ADD ebx,6h ;bei Gelegenheit mal optimieren. NICHT kleiner! ;-------- Restdatei nach "hinten" verschieben MOV ecx,FILELAENGEA SUB ecx,4h SCHIEBEN2: MOV eax,dword[esi-4h+ecx] MOV dword[esi+ecx],eax SUB ecx,4h CMP ecx,edi JAE l_schieben2 ;-------- "UD2" einfügen mit LF --------------------------------------- MOV eax,S3 MOV [esi+edi],eax PUSHAD OpenFile(1,"PureBasic.asm") WriteData(1,*MemoryID,FILELAENGEA) CloseFile(1) PROGID = RunProgram("PBCompiler.exe", PROG$ + ".pb /inlineasm /quiet /reasm /exe " + PROG$ + ".exe", "",#PB_Program_Hide | #PB_Program_Open) WaitProgram(PROGID) CloseProgram(PROGID) OpenFile(2,PROG$ + ".exe") FILELAENGEE=Lof(2) ReadFile(2,PROG$ + ".exe") ReadData(2,*MemoryID+RAMSPEICHER,FILELAENGEE) CloseFile(2) POPAD MOV ecx,RAMSPEICHER ADD ecx,FILELAENGEE MOV ax,0b0fh ;in der EXE-Datei Suche nach Opcode für UD2 (0F0B) SEARCH04: DEC ecx CMP [esi+ecx],ax JNE l_search04 MOV ax,0fh ;max. soviel Bytes zurück verfolgen auf der Suche nach NOP´s FOUND05: DEC ecx CMP Word[esi+ecx],9090h ;2xNOP und damit auch 3xNOP JE l_found06 DEC ax JNZ l_found05 INC bp ;"gut" hier also nur, wenn 1xNOP JMP l_found07 FOUND06: CMP NOPPI,1h JE l_found07 CMP byte[esi-1h+ecx],90h JE l_found07 ;ist 3x NOP INC bp ;-------- Restdatei erstmal wieder nach "vorn" verschieben um 4 Bytes UD2 FOUND07: MOV ecx,FILELAENGEA SUB ecx,4h SCHIEBEN3: MOV eax,dword[esi+4h+edi] MOV dword[esi+edi],eax ADD edi,4h CMP edi,ecx JB l_schieben3 SUB FILELAENGEA,4h POP edi ;Einfügestelle von ALIGN 4 zurückholen OR bp,bp JNE l_genehm ;-------- Restdatei wieder nach "vorn" verschieben um 8 Bytes ALIGN 4 MOV ecx,FILELAENGEA SUB ecx,4h SCHIEBEN4: MOV eax,dword[esi+8h+edi] MOV dword[esi+edi],eax ADD edi,4h CMP edi,ecx JB l_schieben4 SUB FILELAENGEA,8h ;-------- Ende der Verschiebungen GENEHM: XOR bp,bp ;ADD ebx,2h ;-------- Rest der Datei NOFOUND1: INC ebx CMP ebx,FILELAENGEA JB l_search JMP l_fertig NOFOUND3: INC ebx CMP ebx,FILELAENGEA JAE l_fertig CMP byte[esi+ebx],0ah ;LF? JE l_search JMP l_nofound3 NOFOUND4: INC ebx CMP ebx,FILELAENGEA JAE l_fertig CMP byte[esi+ebx],0ah ;LF? JNE l_nofound4 INC ebx JMP l_search ;-------- Unterprogramme WORDTEST: MOV WT,0h ADD ebx,3h LEERW: INC ebx MOV eax,[esi+ebx] AND eax,edx OR al,al JE l_leerw CMP eax,M2 ;WORD JNE l_nofound2 MOV WT,1h NOFOUND2: RET ;-------- Ende der Vorstellung FERTIG: OpenFile(1,"PureBasic.asm") WriteData(1,*MemoryID,FILELAENGEA) CloseFile(1) PROGID = RunProgram("PBCompiler.exe", PROG$ + ".pb /inlineasm /quiet /reasm /exe " + PROG$ + Str(NOPPI) + ".exe", "",#PB_Program_Hide | #PB_Program_Open) WaitProgram(PROGID) CloseProgram(PROGID) DEC DURCHLAUF JZ l_fertig1 OpenFile(1,"OldPureBasic1.asm") ReadData(1,*MemoryID,FILELAENGEA1) CloseFile(1) CopyFile("OldPureBasic1.asm","PureBasic.asm") MOV eax,FILELAENGEA1 MOV FILELAENGEA,eax CMP NOPPI2,0h JNE l_noppi22 MOV NOPPI,1h JMP l_search0 NOPPI22: MOV NOPPI2,0h MOV NOPPI,2h JMP l_search0 FERTIG1: DeleteFile(PROG$ + ".exe") ENDTIME = ElapsedMilliseconds() GESTIME = ENDTIME - STARTTIME GESTIME$ = Str(GESTIME) MessageRequester("Status", "Geschafft in " + GESTIME$ + " Milli-Sekunden !") End ; IDE Options = PureBasic v4.00 - Beta 11 (Windows - x86) ; CursorPosition = 729 ; FirstLine = 708 ; Folding = - ; EnableAsm ; Executable = AliSet.exe ; DisableDebugger