Tutorial AutoIt und Assembler UPDATE 24. Oktober 2010 Verwendung von Autoitvariablen im Assemblercode

  • Beispiel Verwendung von Floatingpoint-Registern und ein Versuch, ein AutoIt-Script 1:1 in Assembler umzusetzen

    Für Berechnungen mit Fließkommazahlen (bis zu 80 Bit Genauigkeit) verwende ich den "Coprozessor" mit seinem eigenen Registerstack (ST0 bis ST7)
    alle Coprozessorbefehle fangen mit F an, also FADD, FMUL, FDIV usw.
    Zunächst muss der Copro mit FINIT initialisiert werden.

    Die Coprozessorbefehle arbeiten (fast) alle mit dem internen Stack. Um nun 2 Zahlen zu multiplizieren, lädt man beide Zahlen per FLD auf den Stack und multipliziert dann:

    ACHTUNG! Ab jetzt wird ST0 in EAX zurückgegeben, um also schnell mal das aktuelle Register auf dem Coprozessorstack (ST0) im Programm zu checken, einfach ein RET hinter den entsprechenden Befehl setzen, dabei im Dll-Call den Rückgabetyp entweder auf float oder double setzen.

    Das Programm "Tunnelflug" habe ich freundlicherweise von UEZ bekommen, der es wiederum von einem JavaScript abgekupfert hat^^
    AutoIt-Version: (jaja, sieht wüst aus, aber so habe ich es bekommen^^)

    Spoiler anzeigen
    [autoit]

    ;Idea taken from http://js1k.com/demo/462
    ;Ported to AutoIt by UEZ Build 2010-08-20
    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_Run_Obfuscator=y
    #Obfuscator_Parameters=/sf /sv /om /cs=0 /cn=0
    #AutoIt3Wrapper_Run_After=del /f /q "Star Burst_Obfuscated.au3"
    #AutoIt3Wrapper_Run_After=upx.exe --ultra-brute "%out%"
    ;~ #AutoIt3Wrapper_Run_After=upx.exe --best "%out%"
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    ;Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $hGUI, $hGraphics, $hBackbuffer, $hBitmap
    Local $H = 132, $W = 132
    ; Initialize GDI+
    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("GDI+ Test", $W, $H)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($W, $H, $hGraphics)
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    ; Using antialiasing
    ;~ _GDIPlus_GraphicsSetSmoothingMode($hBackbuffer, 0)
    ; Create a Brush object
    Local $hBrush = _GDIPlus_BrushCreateSolid()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    adlibregister("_fps",1000)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    global $pi = ACos(-1), $pi2 = 2 * $pi, $pi05 = ACos(-1) * 0.5, $fps
    Local $HW = $H * 0.5, $HH = $W * 0.5
    Local $A0 = 0, $A1 = 0, $A2 = 0, $A3 = 0
    Local $ox = 0, $oy = 0, $0z = 0
    Local $tu = 0, $tv = 0
    Local $speed = 2
    Local $i, $j, $x, $y, $o
    Local $cc, $ss, $z, $col
    Local $dx, $dy, $dz, $rd, $A, $B, $C, $R, $t1, $tu, $tv, $q, $g, $l
    Local $d[$W + 1]

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    While 1;Sleep(10)
    _GDIPlus_GraphicsClear($hBackbuffer, 0xFF000000)
    $o = 0
    For $i = 0 To $H Step $speed
    For $j = 0 To $W Step $speed
    $dx=($j-$HW)/$W;
    $dy=($i-$HH)/$H;
    $dz=-1;
    $l=Sqrt($dx*$dx+$dy*$dy+$dz*$dz);
    $dx/=$l;
    $dy/=$l;
    $dz/=$l;
    $X=$dx;
    $Y=$dy;
    ;//rotate(A0-A2);
    $dy=$Y;
    $Y=$dz;
    $dx=$X;
    $X=$dy;
    ;//rotate(A3);
    $dy=$X;
    $dz=$Y;
    $R=100;
    $A=$dx*$dx+$dy*$dy;
    $B=2*($dx*$ox+$dy*$oy);
    $C=$ox*$ox+$oy*$oy-$R*$R;
    $rd=Sqrt($B*$B-4*$A*$C);
    $q=-.5*($B-$rd);
    $t1=$C/$q;
    $tu=5*ATan2($dy,$dx)/$Pi2;
    $tv=$dz*$t1/256;
    $tv+=$A1;
    $g = Hex(bitand(Bitxor(int($tu * 256), int($tv * 256)), 0xFF), 2)
    $col = "0xFF" & $g & $g & $g
    _GDIPlus_BrushSetSolidColor($hBrush, $col)
    _GDIPlus_GraphicsFillRect($hBackbuffer, $j, $i, $speed, $speed, $hBrush)
    ; $o += 1
    Next
    ; $A0 += 0.015

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;~ $A2 += 0.041
    ;~ $A3 += 0.009
    Next
    $A1 += 0.07

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $W, $H)
    $fps+=1
    ; ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $A1 = ' & $A1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    func _FPS()
    winsettitle($hgui,"",$FPS)
    $FPS=0
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Rotate($t)
    $cc = Cos($t)
    $ss = Sin($t)
    $z = $x * $cc - $y * $ss
    $y = $x * $ss + $y * $cc
    $x = $z
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    func atan2($y,$x)
    return (2*atan($y/($x+sqrt($x*$x+$y*$y))))
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func ATan2_UEZ($y,$x)
    Switch $x
    Case ($x > 0)
    Return ATan($y / $x)
    Case ($x < 0 And $y >= 0)
    Return ATan($y / $x + $pi)
    Case ($x < 0 And $y < 0)
    Return ATan($y / $x - $pi)
    Case ($x = 0 And $y > 0)
    Return $pi05
    Case ($x = 0 And $y < 0)
    Return -$pi05
    Case ($x = 0 And $y = 0)
    Return 0
    EndSwitch
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    ; Clean up
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hBackbuffer)
    _GDIPlus_GraphicsDispose($hGraphics)

    [/autoit] [autoit][/autoit] [autoit]

    ; Uninitialize GDI+
    _GDIPlus_Shutdown()
    Exit
    EndFunc

    [/autoit]

    Umsetzung in Assembler, ich habe versucht, die Rechenschritte im AutoIt-Programm direkt in Assemblerbefehle umzusetzen^^
    Die eigentliche Stärke des Coprozessors, OHNE Zugreifen auf Prozessorregister (EAX, EBX usw) und Speicher, sondern nur mit den eigenen 8 ST-Registern zu arbeiten (parallel zum Prozessor! ) habe ich hier NICHT ausgespielt!
    Im Apfelmännchen habe ich das wesentlich besser gelöst, aber das war mir dann für ein TUT doch etwas heavy^^
    Weiterhin werden extrem viele Speicherschreib- und Lesebefehle durchgeführt. Da die Cachelines jedes mal mit "falschen" Daten gefüllt sind, ist das ein sehr schönes Beispiel, wie man auch mit Assembler SEHR langsame Programme erstellen kann! aber es ist wesentlich schneller als das AutoIt-Script^^ (wobei mein Opera mit dem compilierten Javacode fast ähnlich schnell ist! )

    Spoiler anzeigen
    [autoit]

    #include <FASM.au3>
    #include <MemoryDll.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>
    #include <GDIConstants.au3>
    #include <array.au3>
    #include <GUIConstantsEx.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    $b=520
    $h=520

    [/autoit] [autoit][/autoit] [autoit]

    global $Fasm = FasmInit(), $FPS
    _createbytecode() ;assemblercode erstellen

    [/autoit] [autoit][/autoit] [autoit]

    ;backbuffer erstellen für die Bitmap
    local $ptr_bitmap,$hbmp_bitmap ;byref
    $hDC_bitmap=_CreateNewBmp32($b, $h, $ptr_bitmap,$hbmp_bitmap) ;DC, Pointer auf die Bitmapdaten und ein Handle für GDI+....eine eierlegende Wollmilchsau

    [/autoit] [autoit][/autoit] [autoit]

    $hgui=guicreate("",$b,$h,1,1)
    $hdc_gui=_WinAPI_GetDC($hgui)
    guisetstate()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    adlibregister("_fps",1000) ;FramesPerSecond

    [/autoit] [autoit][/autoit] [autoit]

    $step=0.07 ;das ist die Schrittweite, um die der Tunnelflug ein Frame weiter gezeichnet wird

    [/autoit] [autoit][/autoit] [autoit]

    $struct_a=dllstructcreate("float") ;
    dllstructsetdata($struct_a,1,$step) ;zähler, wird nach jedem Frame um $step erhöht

    [/autoit] [autoit][/autoit] [autoit]

    while 1;sleep(20)
    $Ret = MemoryFuncCall("int", FasmGetFuncPtr($Fasm), "int", $b,"int",$h,"float",dllstructgetdata($struct_a,1),"ptr", $ptr_bitmap)
    _winapi_bitblt($hdc_gui,0,0,$b,$h,$hDC_bitmap,0,0,$srccopy) ;bitmap in die GUI blitten
    $fps+=1
    dllstructsetdata($struct_a,1,dllstructgetdata($struct_a,1)+$step) ;zähler erhöhen
    wend

    [/autoit] [autoit][/autoit] [autoit]

    func _fps()
    winsettitle($hgui,"",$fps)
    $fps=0
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    func _createbytecode()

    [/autoit] [autoit][/autoit] [autoit]

    FasmReset($Fasm)

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "use32")
    FasmAdd($Fasm, "org " & FasmGetBasePtr($Fasm))
    FasmAdd($Fasm, "mov eax,[esp+4]") ;breite
    FasmAdd($Fasm, "mov [breite],eax") ;
    FasmAdd($Fasm, "mov eax,[esp+8]") ;hoehe
    FasmAdd($Fasm, "mov [hoehe],eax") ;
    FasmAdd($Fasm, "mov eax,[esp+12]") ;A1
    FasmAdd($Fasm, "mov [va1],eax") ;
    FasmAdd($Fasm, "mov edi,[esp+16]") ;Ptr auf bitmapdaten
    ;FasmAdd($Fasm, "mov [bitmap],eax") ;

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "FINIT") ;copro init

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "mov dword[vo],0") ; init
    FasmAdd($Fasm, "mov dword[vi],0") ;schleifenzähler
    FasmAdd($Fasm, "mov dword[vj],0") ;
    FasmAdd($Fasm, "mov eax,dword[breite]") ;HW=BREITE/2
    FasmAdd($Fasm, "shr eax,1") ;
    FasmAdd($Fasm, "mov [vhw],eax") ;
    FasmAdd($Fasm, "mov eax,dword[hoehe]") ;HH=HOEHE/2
    FasmAdd($Fasm, "shr eax,1") ;
    FasmAdd($Fasm, "mov [vhh],eax") ;

    [/autoit] [autoit][/autoit] [autoit]

    ;schleifen
    FasmAdd($Fasm, "mov edx,[hoehe]") ;
    FasmAdd($Fasm, "i_schleife:") ; for i=0 to h
    FasmAdd($Fasm, "mov ecx,[breite]") ; schleifenzähler breite
    FasmAdd($Fasm, "j_schleife:") ; for j=0 to w

    [/autoit] [autoit][/autoit] [autoit]

    ;~ ;$dx=($j-$HW)/$W;
    FasmAdd($Fasm, "fild dword[vj]") ;st(0)=j
    FasmAdd($Fasm, "fisub dword[vhw]") ;st(0)=j-hw
    FasmAdd($Fasm, "fidiv dword[breite]");st(0)=(j-hw)/w
    FasmAdd($Fasm, "fst dword[vdx]") ;dx speichern
    FasmAdd($Fasm, "fmul st0,st0") ;st(0)=dx^2 ;26
    ;$dy=($i-$HH)/$H
    FasmAdd($Fasm, "fild [vi]") ;st(0)=i
    FasmAdd($Fasm, "fisub [vhh]") ;st(0)=i-hh
    FasmAdd($Fasm, "fidiv [hoehe]") ;st(0)=(j-hw)/h
    FasmAdd($Fasm, "fst dword[vdy]") ;dy speichern
    ;dz=-1
    FasmAdd($Fasm, "mov [vdz],-1") ;dz=-1
    ;$l=Sqrt($dx*$dx+$dy*$dy+$dz*$dz);
    FasmAdd($Fasm, "fmul st0,st0") ;st(0)=dy^2 st(1)= dx^2
    FasmAdd($Fasm, "fadd st0,st1") ;st(0) =dx^2+dy^2
    FasmAdd($Fasm, "fld1") ;st(0) =1
    FasmAdd($Fasm, "fadd st0,st1") ;st(0) =dx^2+dy^2+1
    FasmAdd($Fasm, "fsqrt") ;st(0)= sqrt(dx^2+dy^2+1)
    ;dx=dx/l
    FasmAdd($Fasm, "fld [vdx]") ;st0=dx st1=l
    FasmAdd($Fasm, "fdiv st0,st1") ;st0=dx/l
    FasmAdd($Fasm, "fstp dword[vdx]") ;dx=dx/l
    ;dy=dy/l
    FasmAdd($Fasm, "fld [vdy]") ;st0=dy st1=l
    FasmAdd($Fasm, "fdiv st0,st1") ;st0=dy/l
    FasmAdd($Fasm, "fstp dword[vdy]") ;dy=dy/l
    ;dz=dz/l
    FasmAdd($Fasm, "fild [vdz]") ;st0=dz st1=l
    FasmAdd($Fasm, "fdiv st0,st1") ;st0=dz/l
    FasmAdd($Fasm, "fstp dword[vdz]") ;dz=dz/l
    ;x=dx
    FasmAdd($Fasm, "mov eax,[vdx]") ;
    FasmAdd($Fasm, "mov [vx],eax") ;
    ;y=dy
    FasmAdd($Fasm, "mov eax,[vdy]") ;
    FasmAdd($Fasm, "mov [vy],eax") ;
    ;dy=y
    FasmAdd($Fasm, "mov eax,[vy]") ;
    FasmAdd($Fasm, "mov [vdy],eax") ;
    ;y=dz
    FasmAdd($Fasm, "mov eax,[vdz]") ;
    FasmAdd($Fasm, "mov [vy],eax") ;
    ;dx=x
    FasmAdd($Fasm, "mov eax,[vx]") ;
    FasmAdd($Fasm, "mov [vdx],eax") ;
    ;x=dy
    FasmAdd($Fasm, "mov eax,[vdy]") ;
    FasmAdd($Fasm, "mov [vx],eax") ;
    ;dy=x
    FasmAdd($Fasm, "mov eax,[vx]") ;
    FasmAdd($Fasm, "mov [vdy],eax") ;
    ;dz=y
    FasmAdd($Fasm, "mov eax,[vy]") ;
    FasmAdd($Fasm, "mov [vdz],eax") ;
    ;r=10000 ist konstante
    ;$A=$dx*$dx+$dy*$dy;
    FasmAdd($Fasm, "fld [vdx]") ;st0=dx
    FasmAdd($Fasm, "fmul st0,st0") ;st0=dx^2
    FasmAdd($Fasm, "fld [vdy]") ;st0=dy
    FasmAdd($Fasm, "fmul st0,st0") ;st0=dy^2 st1=dx^2
    FasmAdd($Fasm, "fadd st0,st1") ;st0 =dx^2+dy^2
    FasmAdd($Fasm, "fstp dword[va]") ;a=dx^2+dy^2
    ;$B=2*($dx*$ox+$dy*$oy) = 0;
    ;$c=-10000 =konstante
    ;$rd=Sqrt($B*$B-4*$A*$C);
    FasmAdd($Fasm, "fld [minusvier]") ;st0=-4 69
    FasmAdd($Fasm, "fmul [va]") ;st0=-4*a
    FasmAdd($Fasm, "fmul [vc]") ;st0=-4*a*c
    FasmAdd($Fasm, "fsqrt") ;st0=-4*a*c
    ; $q=-.5*($B-$rd)
    FasmAdd($Fasm, "fldz ") ;st0=b=0 st1==rd
    FasmAdd($Fasm, "fsub st0,st1") ;st0=(b-rd) st1=rd
    FasmAdd($Fasm, "fmul [minuseinhalb]") ;st0=-0.5*(B-rd)=q
    FasmAdd($Fasm, "fstp dword[vq]") ;

    [/autoit] [autoit][/autoit] [autoit]

    ;~ ; $tu=5*ATan2($dy,$dx)/$Pi2;
    FasmAdd($Fasm, "fld [vdx]") ;st0 =vdx
    FasmAdd($Fasm, "fld [vdy]") ;
    FasmAdd($Fasm, "fpatan") ;
    FasmAdd($Fasm, "fmul [fuenf]") ;
    FasmAdd($Fasm, "fldpi") ;
    FasmAdd($Fasm, "fdivp st1,st0") ;
    FasmAdd($Fasm, "fdiv [zwei]") ;st0=tu
    FasmAdd($Fasm, "fistp [vtu]") ;tu
    ; $tv=$dz*$c/q/256;
    FasmAdd($Fasm, "fld [vdz]") ;st0=dz
    FasmAdd($Fasm, "fmul [vc]") ;
    FasmAdd($Fasm, "fdiv [vq]") ;
    FasmAdd($Fasm, "fdiv [v256]") ;
    FasmAdd($Fasm, "fadd [va1]") ;tv
    FasmAdd($Fasm, "fst [vtv]") ;tv=tv+a1
    FasmAdd($Fasm, "fmul [v256]") ;tv
    FasmAdd($Fasm, "fistp [vtv1]") ;tv

    [/autoit] [autoit][/autoit] [autoit]

    ;stack cleanen
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop
    FasmAdd($Fasm, "fstp st0") ;pop

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "mov eax,[vtv1]") ;
    FasmAdd($Fasm, "xor eax,[vtu]") ;
    FasmAdd($Fasm, "and eax,0xFF") ;farbe von RR, GG und BB
    ;FasmAdd($Fasm, "ret 16");Funktionsende

    [/autoit] [autoit][/autoit] [autoit]

    ;pixelfarbe (grauton) erstellen
    FasmAdd($Fasm, "mov ebx,0xFF") ;alpha AA
    FasmAdd($Fasm, "shl ebx,8") ;AA00
    FasmAdd($Fasm, "or ebx,eax") ;AABB
    FasmAdd($Fasm, "shl ebx,8") ;AABB00
    FasmAdd($Fasm, "or ebx,eax") ;AABBGG
    FasmAdd($Fasm, "shl ebx,8") ;AABBGG00
    FasmAdd($Fasm, "or eax,ebx") ;AABBGGRR

    [/autoit] [autoit][/autoit] [autoit]

    ;FasmAdd($Fasm, "ret 16");Funktionsende
    ;FasmAdd($Fasm, "mov eax,0xFF00FF00") ;AABBGGRR
    FasmAdd($Fasm, "stosd") ;mov [edi],eax pixel in die bitmap schreiben
    FasmAdd($Fasm, "dec ecx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "mov [vj],ecx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "jnz j_schleife") ;so lange bis 0

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "dec edx") ;schleifenzähler hoehe
    FasmAdd($Fasm, "mov [vi],edx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "jnz i_schleife") ;so lange bis 0

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "ret 16");Programmende

    [/autoit] [autoit][/autoit] [autoit]

    ;variablen, einige werden nicht gebraucht, habe aber versucht, das AutoItscript zu übernehmen

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "v256 dd 256.0") ;eigentlich konstanten....
    FasmAdd($Fasm, "zwei dd 2.0")
    FasmAdd($Fasm, "minusvier dd -4.0")
    FasmAdd($Fasm, "fuenf dd 1280.0")
    FasmAdd($Fasm, "minuseinhalb dd -0.5")
    FasmAdd($Fasm, "bitmap dd 0")
    FasmAdd($Fasm, "breite dd 0")
    FasmAdd($Fasm, "hoehe dd 0")
    FasmAdd($Fasm, "vhw dd 0")
    FasmAdd($Fasm, "vhh dd 0")
    FasmAdd($Fasm, "vo dd 0.0")
    FasmAdd($Fasm, "vi dd 0.0")
    FasmAdd($Fasm, "vj dd 0.0")
    FasmAdd($Fasm, "vl dd 0.0")
    FasmAdd($Fasm, "vdx dd 0.0")
    FasmAdd($Fasm, "vdy dd 0.0")
    FasmAdd($Fasm, "vdz dd 0.0")
    FasmAdd($Fasm, "vx dd 0.0")
    FasmAdd($Fasm, "vy dd 0.0")
    FasmAdd($Fasm, "vr dd 10000.0")
    FasmAdd($Fasm, "va dd 0.0")
    FasmAdd($Fasm, "vb dd 0.0")
    FasmAdd($Fasm, "vc dd -10000.0")
    FasmAdd($Fasm, "vrd dd 0.0")
    FasmAdd($Fasm, "vq dd 0.0")
    FasmAdd($Fasm, "vt1 dd 0.0")
    FasmAdd($Fasm, "vtu dd 0")
    FasmAdd($Fasm, "vtv dd 0")
    FasmAdd($Fasm, "vtv1 dd 0")
    FasmAdd($Fasm, "va1 dd 0.00005")

    [/autoit] [autoit][/autoit] [autoit]

    $Binary = FasmGetBinary($Fasm) ;syntaxerror im Assembler abfangen abfangen
    ;~ If @Extended Then ;syntax-error aufgetreten
    ;~ $Error = FasmGetLastError()
    ;~ ConsoleWrite("Error Code:" & $Error[0] & @CRLF & "Error Message:" & $Error[1] & @CRLF & "Error Line:" & $Error[2] & @CRLF)
    ;~ Else ;syntax ok
    ConsoleWrite(String(FasmGetBinary($Fasm)) & @CRLF)
    filedelete("test.bin") ;assembly für externen debugger
    filewrite("test.bin",binarytostring(String(FasmGetBinary($Fasm))))

    [/autoit] [autoit][/autoit] [autoit]

    endfunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe DC und ptr und handle auf die Bitmapdaten
    ;by Andy
    Local $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    Local $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    ;_arraydisplay($adib)
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

    [/autoit]

    übrigens habe ich auf einem AMD4850@2,5Ghz bei einer Fenstergröße von 320x320 ca 55FPS und bei 800x800 nur noch 5-6 FPS^^

    und der JS-Code

    Spoiler anzeigen

    einfach als HTML speichern und aufrufen

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    5 Mal editiert, zuletzt von Andy (24. August 2010 um 00:58)

  • Optimierung von Code am Beispiel des Tunnelfluges

    Wer das Beispiel im vorherigen Post durchgegangen ist, der hat wahrscheinlich den Kopf geschüttelt ob so viel Unfähigkeit des Programmierers^^
    Warum?
    Nun, wir (ich) haben ein AutoItScript nach Assembler portiert, aber dieses gemacht, OHNE NACHZUDENKEN!
    Allein das AutoItScript hat reichlich Kürzungs- und Optimierungsbedarf!
    Selbst mit geringen mathematischen Kenntnissen, kommt man auf folgendes Script:

    Spoiler anzeigen
    [autoit]

    ;Idea taken from http://js1k.com/demo/462
    ;Ported to AutoIt by UEZ Build 2010-08-20
    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_Run_Obfuscator=y
    #Obfuscator_Parameters=/sf /sv /om /cs=0 /cn=0
    #AutoIt3Wrapper_Run_After=del /f /q "Star Burst_Obfuscated.au3"
    #AutoIt3Wrapper_Run_After=upx.exe --ultra-brute "%out%"
    ;~ #AutoIt3Wrapper_Run_After=upx.exe --best "%out%"
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    ;Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $hGUI, $hGraphics, $hBackbuffer, $hBitmap
    Local $H = 332, $W = 332
    ; Initialize GDI+
    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("GDI+ Test", $W, $H)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($W, $H, $hGraphics)
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    ; Using antialiasing
    ;~ _GDIPlus_GraphicsSetSmoothingMode($hBackbuffer, 0)
    ; Create a Brush object
    Local $hBrush = _GDIPlus_BrushCreateSolid()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    [/autoit] [autoit][/autoit] [autoit]

    adlibregister("_fps",1000)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    global $pi = ACos(-1), $pi2 = 2 * $pi, $pi05 = ACos(-1) * 0.5, $fps
    Local $HW = $H * 0.5, $HH = $W * 0.5
    Local $A0 = 0, $A1 = 0, $A2 = 0, $A3 = 0
    Local $ox = 0, $oy = 0, $0z = 0
    Local $tu = 0, $tv = 0
    Local $speed = 2
    Local $i, $j, $x, $y, $o
    Local $cc, $ss, $z, $col
    Local $dx, $dy, $dz, $rd, $A, $B, $C, $R, $t1, $tu, $tv, $q, $g, $l
    Local $d[$W + 1]

    [/autoit] [autoit][/autoit] [autoit]

    $zwonulldrei=203.718330632686
    $nulldrei=0.390625
    ;$a1=0.07

    [/autoit] [autoit][/autoit] [autoit]

    While 1;Sleep(10)
    _GDIPlus_GraphicsClear($hBackbuffer, 0xFF000000)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To $H Step $speed
    For $j = 0 To $W Step $speed
    $dx=($j/$W)-0.5;
    $dy=($i/$H)-0.5;
    $tu=int($zwonulldrei*ATan2($dy,$dx))
    $tv=($nulldrei/sqrt($dx*$dx+$dy*$dy))+$A1
    $tv=int($tv*256)
    $g = Hex(bitand(Bitxor($tu , $tv), 0xFF), 2)
    $col = "0xFF" & $g & $g & $g
    _GDIPlus_BrushSetSolidColor($hBrush, $col)
    _GDIPlus_GraphicsFillRect($hBackbuffer, $j, $i, $speed, $speed, $hBrush)

    [/autoit] [autoit][/autoit] [autoit]

    Next
    Next
    $A1 += 0.07

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $W, $H)
    $fps+=1
    ; ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $A1 = ' & $A1 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    func _FPS()
    winsettitle($hgui,"",$FPS)
    $FPS=0
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Rotate($t)
    $cc = Cos($t)
    $ss = Sin($t)
    $z = $x * $cc - $y * $ss
    $y = $x * $ss + $y * $cc
    $x = $z
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    func atan2($y,$x)
    return (2*atan($y/($x+sqrt($x*$x+$y*$y))))
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func ATan2_UEZ($y,$x)
    Switch $x
    Case ($x > 0)
    Return ATan($y / $x)
    Case ($x < 0 And $y >= 0)
    Return ATan($y / $x + $pi)
    Case ($x < 0 And $y < 0)
    Return ATan($y / $x - $pi)
    Case ($x = 0 And $y > 0)
    Return $pi05
    Case ($x = 0 And $y < 0)
    Return -$pi05
    Case ($x = 0 And $y = 0)
    Return 0
    EndSwitch
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    ; Clean up
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hBackbuffer)
    _GDIPlus_GraphicsDispose($hGraphics)

    [/autoit] [autoit][/autoit] [autoit]

    ; Uninitialize GDI+
    _GDIPlus_Shutdown()
    Exit
    EndFunc

    [/autoit]

    Das sieht schon anders aus!
    Viele Variablen sind verschwunden und jede Menge Rechnerei auch!

    Da wir nun nicht mehr so viele Variablen haben, optimieren wir unseren Assemblercode so, daß wir die Variablen auf dem Stack des Coprozessors lagern.
    Anstatt langsam auf SPEICHER zuzugreifen, holen wir die Variablen aus dem schnellen Register-STACK des Prozessors.
    Ein FMUL ST0,ST4 ist wesentlich schneller als ein FMUL [Speicherstelle]!
    Leider passen nicht alle Variablen auf den Stack, so daß wir immer noch ein wenig Speed verschenken, aber durch die ERSTE Optimierung haben wir die Geschwindigkeit des Programms nahezu verdoppelt!

    Spoiler anzeigen
    [autoit]

    #include <FASM.au3>
    #include <MemoryDll.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>
    #include <GDIConstants.au3>
    #include <array.au3>
    #include <GUIConstantsEx.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    $b=520
    $h=520

    [/autoit] [autoit][/autoit] [autoit]

    global $Fasm = FasmInit(), $FPS
    _createbytecode() ;assemblercode erstellen

    [/autoit] [autoit][/autoit] [autoit]

    ;backbuffer erstellen für die Bitmap
    local $ptr_bitmap,$hbmp_bitmap ;byref
    $hDC_bitmap=_CreateNewBmp32($b, $h, $ptr_bitmap,$hbmp_bitmap) ;DC, Pointer auf die Bitmapdaten und ein Handle für GDI+....eine eierlegende Wollmilchsau

    [/autoit] [autoit][/autoit] [autoit]

    $hgui=guicreate("",$b,$h,1,1)
    $hdc_gui=_WinAPI_GetDC($hgui)
    guisetstate()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    adlibregister("_fps",1000) ;FramesPerSecond

    [/autoit] [autoit][/autoit] [autoit]

    $step=0.07 ;das ist die Schrittweite, um die der Tunnelflug ein Frame weiter gezeichnet wird

    [/autoit] [autoit][/autoit] [autoit]

    $struct_a=dllstructcreate("float") ;
    dllstructsetdata($struct_a,1,$step) ;zähler, wird nach jedem Frame um $step erhöht

    [/autoit] [autoit][/autoit] [autoit]

    while 1;sleep(20)
    $Ret = MemoryFuncCall("int", FasmGetFuncPtr($Fasm), "int", $b,"int",$h,"float",dllstructgetdata($struct_a,1),"ptr", $ptr_bitmap)
    _winapi_bitblt($hdc_gui,0,0,$b,$h,$hDC_bitmap,0,0,$srccopy) ;bitmap in die GUI blitten
    $fps+=1
    dllstructsetdata($struct_a,1,dllstructgetdata($struct_a,1)+$step) ;zähler erhöhen
    wend

    [/autoit] [autoit][/autoit] [autoit]

    func _fps()
    winsettitle($hgui,"",$fps)
    $fps=0
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    func _createbytecode()

    [/autoit] [autoit][/autoit] [autoit]

    FasmReset($Fasm)

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "use32")
    FasmAdd($Fasm, "org " & FasmGetBasePtr($Fasm))
    FasmAdd($Fasm, "mov eax,[esp+4]") ;breite
    FasmAdd($Fasm, "mov [breite],eax") ;
    FasmAdd($Fasm, "mov eax,[esp+8]") ;hoehe
    FasmAdd($Fasm, "mov [hoehe],eax") ;
    FasmAdd($Fasm, "mov eax,[esp+12]") ;A1
    FasmAdd($Fasm, "mov [va1],eax") ;
    FasmAdd($Fasm, "mov edi,[esp+16]") ;Ptr auf bitmapdaten
    ;FasmAdd($Fasm, "mov [bitmap],eax") ;

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "FINIT") ;copro init

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "mov dword[vi],0") ;schleifenzähler
    FasmAdd($Fasm, "mov dword[vj],0") ;

    [/autoit] [autoit][/autoit] [autoit]

    ;stack mit konstanten laden, diese bleiben während des gesamten durchlaufs im stack!
    FasmAdd($Fasm, "fld1") ;st0=1
    FasmAdd($Fasm, "fidiv [hoehe] ") ;st0=1/h
    FasmAdd($Fasm, "fld [minuseinhalb]") ;st0=-0.5
    FasmAdd($Fasm, "fld [zwonulldrei]") ;st0=203.xx st1=-0.5
    FasmAdd($Fasm, "fld [nulldrei]") ;st0=0.39 st1=203.xx st2=-0.5 st3=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;leider hat die inverse breite keinen platz mehr auf dem stack gefunden und muss in speicher gelagert werden
    FasmAdd($Fasm, "fld1") ;st0=1 st1=breite
    FasmAdd($Fasm, "fidiv [breite]") ;st0=1/b
    FasmAdd($Fasm, "fstp [invbreite]") ;st0=0.39 st1=203.xx st2=-0.5 st3=1/h 21

    [/autoit] [autoit][/autoit] [autoit]

    ;schleifen
    FasmAdd($Fasm, "mov edx,[hoehe]") ;
    FasmAdd($Fasm, "i_schleife:") ; for i=0 to h
    FasmAdd($Fasm, "mov ecx,[breite]") ; schleifenzähler breite
    FasmAdd($Fasm, "j_schleife:") ; for j=0 to w

    [/autoit] [autoit][/autoit] [autoit]

    ;~ ;$dx=($j-$HW)/$W;
    FasmAdd($Fasm, "fild dword[vj]") ;st0=j st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fmul [invbreite] ") ;st(0)=j/w
    FasmAdd($Fasm, "fadd st0,st3") ;st(0)=j/w-0.5 st1=0.39 st2=203.xx st3=-0.5 st4=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;$dy=($i-$HH)/$H
    FasmAdd($Fasm, "fild [vi]") ;st0=i st1=dx st2=0.39 st3=203.xx st4=-0.5 st5=1/h
    FasmAdd($Fasm, "fmul st0,st5") ;st(0)=i/h
    FasmAdd($Fasm, "fadd st0,st4") ;st(0)=i/h-0.5=dy st1=dx st2=0.39 st3=203.xx st4=-0.5 st5=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;$tu=int($5div2pi*ATan2($dy,$dx))
    FasmAdd($Fasm, "fld st0") ;st0=dy st1=dy st2=dx
    FasmAdd($Fasm, "fld st2") ;st0=dx st1=dy st2=dy st3=dx st4=0.39 st5=203.xx st6=-0.5 st7=1/h
    ;weil atan2 2 stackplätze "verbraucht" bzw zerstört, konnte 1/b nicht auf den stack!
    FasmAdd($Fasm, "fpatan") ;st0=atan2 st1=dy st2=dx st3=0.39 st4=203.xx st5=-0.5 st6=1/h
    FasmAdd($Fasm, "fmul st0,st4") ;st0=atan2*203
    FasmAdd($Fasm, "fistp [vtu]") ;st0=dy st1=dx st2=0.39 st3=203.xx st4=-0.5 st5=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;$tv=($nulldrei/sqrt($dx*$dx+$dy*$dy))+$a1
    FasmAdd($Fasm, "fmul st0,st0") ;st0=dy^2 st1=dx st2=0.39 st3=203.xx st4=-0.5 st5=1/h

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "fxch") ;st0=dx st1=dy^2 st2=0.39 st3=203.xx st4=-0.5 st5=1/h
    FasmAdd($Fasm, "fmul st0,st0") ;st0=dx^2 st1=dy^2 st2=0.39 st3=203.xx st4=-0.5 st5=1/h
    FasmAdd($Fasm, "faddp ") ;st0=dy^2+dx^2 st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fsqrt") ;st0=sqrt(dy^2+dx^2) st1=0.39 st2=203.xx st3=-0.5 st4=1/h

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "fdivr st0,st1 ");st0=0.3/sqrt st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fadd [va1]") ;st0=0.3/sqrt+a1 st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fimul [v256]") ;st0=(0.3/sqrt+a1)*256 st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fistp [vtv]") ;st0=0.39 st1=203.xx st2=-0.5 st3=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;stack ist in dem zustand, wie er am anfang der schleife war

    [/autoit] [autoit][/autoit] [autoit]

    ;XOR
    FasmAdd($Fasm, "mov eax,[vtv]") ;
    FasmAdd($Fasm, "xor eax,[vtu]") ;
    FasmAdd($Fasm, "and eax,0xFF") ;farbe von RR, GG und BB
    ;pixelfarbe (grauton) erstellen
    FasmAdd($Fasm, "mov ebx,0xFF") ;alpha AA
    FasmAdd($Fasm, "shl ebx,8") ;AA00
    FasmAdd($Fasm, "or ebx,eax") ;AABB
    FasmAdd($Fasm, "shl ebx,8") ;AABB00
    FasmAdd($Fasm, "or ebx,eax") ;AABBGG
    FasmAdd($Fasm, "shl ebx,8") ;AABBGG00
    FasmAdd($Fasm, "or eax,ebx") ;AABBGGRR

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "stosd") ;mov [edi],eax pixel in die bitmap schreiben
    FasmAdd($Fasm, "dec ecx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "mov [vj],ecx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "jnz j_schleife") ;so lange bis 0

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "dec edx") ;schleifenzähler hoehe
    FasmAdd($Fasm, "mov [vi],edx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "jnz i_schleife") ;so lange bis 0

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "ret 16");Programmende

    [/autoit] [autoit][/autoit] [autoit]

    ;variablen, einige werden nicht gebraucht, habe aber versucht, das AutoItscript zu übernehmen

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "nulldrei dd 0.390625") ;100/256
    FasmAdd($Fasm, "zwonulldrei dd 203.718330632686")
    FasmAdd($Fasm, "minuseinhalb dd -0.5")
    FasmAdd($Fasm, "v256 dd 256")
    FasmAdd($Fasm, "hoehe dd 0")
    FasmAdd($Fasm, "breite dd 0")
    FasmAdd($Fasm, "invbreite dd 0.0")
    FasmAdd($Fasm, "va1 dd 0.0")
    FasmAdd($Fasm, "vtu dd 0")
    FasmAdd($Fasm, "vtv dd 0")
    FasmAdd($Fasm, "vi dd 0")
    FasmAdd($Fasm, "vj dd 0")

    [/autoit] [autoit][/autoit] [autoit]

    $Binary = FasmGetBinary($Fasm) ;syntaxerror im Assembler abfangen abfangen
    ;~ If @Extended Then ;syntax-error aufgetreten
    ;~ $Error = FasmGetLastError()
    ;~ ConsoleWrite("Error Code:" & $Error[0] & @CRLF & "Error Message:" & $Error[1] & @CRLF & "Error Line:" & $Error[2] & @CRLF)
    ;~ Else ;syntax ok
    ConsoleWrite(String(FasmGetBinary($Fasm)) & @CRLF)
    filedelete("test.bin") ;assembly für externen debugger
    filewrite("test.bin",binarytostring(String(FasmGetBinary($Fasm))))

    [/autoit] [autoit][/autoit] [autoit]

    endfunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe DC und ptr und handle auf die Bitmapdaten
    ;by Andy
    Local $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    Local $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    ;_arraydisplay($adib)
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

    [/autoit]

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    Einmal editiert, zuletzt von Andy (24. August 2010 um 19:17)

  • Dafür fehlt jetzt aber die Rotation ;)

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Zitat

    Dafür fehlt jetzt aber die Rotation

    Die hat schon immer gefehlt, siehe unverändertes JS-Programm, ich hatte mich die ganze Zeit gefragt, wieso dort nirgendwo die Funktion rotation() aufgerufen wird! /EDIT/ Aaaah, das waren die auskommentierten 2 Zeilen^^ 8o

    Hab mir jetzt mal das Orginal downgeloaded, na gut, bissl Rotation, das macht den Kohl nicht fett, da der FPATAN()-Befehl immer noch die Hälfte der Performance schluckt (bis zu 300 Takte! )
    Um das zu umgehen, müsste man entweder eine "schnelle" Bibliothek einbinden, oder selbst eine Ergebnisliste für FPATAN() erstellen (so wie"früher" im Tabellenbuch für Sinus und Cosinus). Das ist mir zu aufwendig^^

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (24. August 2010 um 16:10)

  • Weitere Optimierung am "Tunnelflug" am Beispiel eines Arrays bzw. LookUpTabelle LUT

    Beim bisherigen "Tunnelflug" war ein Assemblerbefehl FPATAN() enthalten, um kartesische Koordinaten in Polarkoordinaten umzurechnen, siehe ATAN2
    Allein dieser FPATAN() benötigt zur Ausführung bis zu 300 Takte, die Latency beträgt 136 Takte....was das bedeutet interessiert erstmal nicht, aber wenn man mal vergleicht, dass ein ADD in einem Takt ausgeführt wird, ist das ....hmpft..."etwas" viel!
    Wenn man einfach die Zeile im Programm, in dem der FPATAN() Befehl steht, auskommentiert, erhöhen sich die Frames pro Sekunde auf über das Doppelte bis fast zum dreifachen!
    Krass gesagt, EIN einziger Befehl frisst mehr als die Hälfte der Performance des Programms!
    Genau an diesem Punkt fängt die Optimierung an. Man optimiert zuerst nicht am "Kleinkram", sondern immer an "den dicken Brocken"!
    FPATAN() ist solch ein Brocken...

    Wie kann man einen Prozessorbefehl verbessern?
    Nun, der Coprozessor wendet allerfeinste Algorithmen an, um immer genau das richtige Ergebnis der Berechnung auszugeben.
    Wir brauchen aber nicht die 30. Nachkommastelle genau, uns reichen 3-4 Nachkommastellen zum Anzeigen unserer Grafik.
    Also legen wir (wenn BugFix keine Ohren hätte, würde er jetzt im Kreis grinsen^^) ein ARRAY an. Ein Array von Fließkommazahlen mit Tausend Elementen.
    Das Array wird gefüllt mit den berechneten Ergebnissen von arcustangens(0) bis arcustangens von 10.
    Also in AutoIt übersetzt

    [autoit]

    dim $atan_array[1000]
    for $i=0 to 999
    $atan_array[$i]=atan($i/100)
    next

    [/autoit]


    In Assembler legen wir das Array als eine Reihe von Dwords an, Tausend Stück!

    [autoit]

    FasmAdd($Fasm, "atantabelle dd 1000 dup 0") ;array mit 1000 werten für atantabelle[atanindex]=atanvalue erstellen

    [/autoit]


    Wie greift man auf den Inhalt eines Arrays zu? Mit dem Index!
    Wir wissen von unserem "Assemblerarray" die Startadresse (atantabelle) und das jedes Element 4 Byte groß ist.
    Um also auf das 7. Element zuzugreifen, rechnen wir

    Code
    atantabelle(das ist die Startadresse) + 4 * 7 (7 ist der Index)


    um also das 88. Element aus dem Array in das Register EAX zu befördern, schreibt man

    Code
    mov EAX,[atantabelle + 4 * 88]
      ;oder per Indexregister
    mov EBX,88   ;oder jedes andere Register
    mov EAX,[atantabelle + 4 * EBX]


    Genauso beschreibt man das Array

    Code
    mov EBX,88     ;oder jedes andere Register
    mov [atantabelle + 4 * EBX], EAX     ;EAX in das Array eintragen


    OK, wir haben nun ein Array, welches wir mit den Arcustangenswerten füllen können, was soll das nützen?
    Wir müssen, wenn wir einen Wert aus der Tabelle bzw dem Array benötigen, nur den Index haben, um den passenden Wert auszulesen.
    Der Index ist aber gerade das 100-fache unseres gesuchten arcustanges (schaut euch die FOR/TO Schleife im AutoItscript oben an)
    Also nehmen wir unseren Wert von dem wir den arcustangens suchen, z.B. 0,55 , und nehmen den mal 100 und erhalten den Index 0,55*100=55
    In der atantabelle bei Index 55 steht der arcustangens von 0,55....isn´t that easy? :rofl:
    Der Witz ist nun, wir benötigen eine Multiplikation (mal 100), ein bissl Vorzeichengeplänkel, (-0,55 ergäbe einen Index von -55, und den gibts nicht) und einen Vergleich und haben unseren Index ermittelt
    Ich habe nicht nachgezählt, aber mehr als 10-15 Takte sollte das alles nicht dauern. Aber 15 Takte zu 300 ist ein geschmeidiger Wert, wir können uns auf die Schulter hauen!
    Bei der Berechnung eines jeden Pixels im Fenster sparen wir nun 285 Takte ein, bei 1000x1000 Pixel sind das läppische 285 Millionen Takte pro Frame....

    Unser Programm ist zwar 50 Zeilen länger geworden und wir brauchen auch 4 Kilobyte mehr Speicher für das Array, aber die Ausführungsgeschwindigkeit hat sich verdoppelt!
    50 Zeilen und +4kB um EINEN Befehl zu ersetzen? Nun ja...wir sind ja noch lange nicht fertig mit dem optimieren, da geht sicher noch was^^

    Spoiler anzeigen
    [autoit]

    #include <FASM.au3>
    #include <MemoryDll.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>
    #include <GDIConstants.au3>
    #include <array.au3>
    #include <GUIConstantsEx.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;im folgenden Beispiel wird der Befehl FPATAN() der ca 300 Takte braucht, durch einen schnellen Zugriff auf eine LookUp-Tabelle LUT ersetzt
    ;der Geschwindigkeitsgewinn beträgt ca. x2!
    ;die lookuptabelle ist ein Array mit dem Index von 0 bis 1000 und enthält die Werte atan(0) bis atan(10)

    [/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    $b=640 ;Breite und höhe in pixel
    $h=640

    [/autoit] [autoit][/autoit] [autoit]

    global $Fasm = FasmInit(), $FPS
    _createbytecode() ;assemblercode erstellen

    [/autoit] [autoit][/autoit] [autoit]

    ;backbuffer erstellen für die Bitmap
    local $ptr_bitmap,$hbmp_bitmap ;byref
    $hDC_bitmap=_CreateNewBmp32($b, $h, $ptr_bitmap,$hbmp_bitmap) ;DC, Pointer auf die Bitmapdaten und ein Handle für GDI+....eine eierlegende Wollmilchsau

    [/autoit] [autoit][/autoit] [autoit]

    $hgui=guicreate("",$b,$h,1,1)
    $hdc_gui=_WinAPI_GetDC($hgui)
    guisetstate()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    adlibregister("_fps",1000) ;FramesPerSecond

    [/autoit] [autoit][/autoit] [autoit]

    $step=0.02 ;das ist die Schrittweite, um die der Tunnelflug ein Frame weiter gezeichnet wird

    [/autoit] [autoit][/autoit] [autoit]

    $struct_a=dllstructcreate("float") ;
    dllstructsetdata($struct_a,1,$step) ;zähler, wird nach jedem Frame um $step erhöht

    [/autoit] [autoit][/autoit] [autoit]

    while 1;sleep(20)
    $Ret = MemoryFuncCall("float", FasmGetFuncPtr($Fasm), "int", $b,"int",$h,"float",dllstructgetdata($struct_a,1),"ptr", $ptr_bitmap)
    _winapi_bitblt($hdc_gui,0,0,$b,$h,$hDC_bitmap,0,0,$srccopy) ;bitmap in die GUI blitten
    $fps+=1
    dllstructsetdata($struct_a,1,dllstructgetdata($struct_a,1)+$step) ;zähler um step erhöhen
    wend

    [/autoit] [autoit][/autoit] [autoit]

    func _fps()
    winsettitle($hgui,"",$fps&" FPS")
    $fps=0
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    func _createbytecode()

    [/autoit] [autoit][/autoit] [autoit]

    FasmReset($Fasm)

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "use32")
    FasmAdd($Fasm, "org " & FasmGetBasePtr($Fasm))
    FasmAdd($Fasm, "mov eax,[esp+4]") ;breite
    FasmAdd($Fasm, "mov [breite],eax") ;
    FasmAdd($Fasm, "mov eax,[esp+8]") ;hoehe
    FasmAdd($Fasm, "mov [hoehe],eax") ;
    FasmAdd($Fasm, "mov eax,[esp+12]") ;A1
    FasmAdd($Fasm, "mov [va1],eax") ;
    FasmAdd($Fasm, "mov edi,[esp+16]") ;Ptr auf bitmapdaten

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "FINIT") ;copro init 10
    ;die Tabelle mit Werten füllen
    FasmAdd($Fasm, "mov ecx,1000") ;tabellenlimit
    FasmAdd($Fasm, "mov ebx,-1") ;zähler tabellenindex
    ;atantabelle[ebx]=ATAN(ebx/100)
    FasmAdd($Fasm, "_atanschleife:") ;
    FasmAdd($Fasm, "inc ebx") ;index eins höher
    FasmAdd($Fasm, "mov dword [atanindex],ebx ") ;index in speicher
    FasmAdd($Fasm, "fild dword [atanindex]") ;st0=index
    FasmAdd($Fasm, "fidiv dword[hundert]") ;st0=index/100
    FasmAdd($Fasm, "fld1") ;st0=1 st1=index/100
    FasmAdd($Fasm, "fpatan") ; ;st0=atan(st1/st0)
    FasmAdd($Fasm, "fstp dword[atantabelle+ebx*4]") ;atan im atantabelle[index*4] speichern
    FasmAdd($Fasm, "cmp ebx, ecx") ;ist limit erreicht?
    FasmAdd($Fasm, "jne _atanschleife") ;wenn limit noch nicht erreicht, dann nächsten index
    ;lookup-tabelle gefüllt

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "mov dword[vi],0") ;schleifenzähler
    FasmAdd($Fasm, "mov dword[vj],0") ;

    [/autoit] [autoit][/autoit] [autoit]

    ;stack mit konstanten laden, diese bleiben während des gesamten durchlaufs im stack!
    FasmAdd($Fasm, "fld1") ;st0=1
    FasmAdd($Fasm, "fidiv [hoehe] ") ;st0=1/h
    FasmAdd($Fasm, "fld [minuseinhalb]") ;st0=-0.5
    FasmAdd($Fasm, "fld [zwonulldrei]") ;st0=203.xx st1=-0.5
    FasmAdd($Fasm, "fld [nulldrei]") ;st0=0.39 st1=203.xx st2=-0.5 st3=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;leider hat die inverse breite keinen platz mehr auf dem stack gefunden und muss in speicher gelagert werden
    FasmAdd($Fasm, "fld1") ;st0=1 st1=breite
    FasmAdd($Fasm, "fidiv [breite]") ;st0=1/b
    FasmAdd($Fasm, "fstp [invbreite]") ;st0=0.39 st1=203.xx st2=-0.5 st3=1/h 21

    [/autoit] [autoit][/autoit] [autoit]

    ;schleifen
    FasmAdd($Fasm, "mov edx,[hoehe]") ;schleifenzähle höhe
    FasmAdd($Fasm, "i_schleife:") ; for i=0 to h
    FasmAdd($Fasm, "mov ecx,[breite]") ; schleifenzähler breite
    FasmAdd($Fasm, "j_schleife:") ; for j=0 to w

    [/autoit] [autoit][/autoit] [autoit]

    ;~ ;$dx=($j-$HW)/$W;
    FasmAdd($Fasm, "fild dword[vj]") ;st0=j st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fmul [invbreite] ") ;st(0)=j/w
    FasmAdd($Fasm, "fadd st0,st3") ;st(0=j/w-0.5 st1=0.39 st2=203.xx st3=-0.5 st4=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;$dy=($i-$HH)/$H
    FasmAdd($Fasm, "fild [vi]") ;st0=i st1=dx st2=0.39 st3=203.xx st4=-0.5 st5=1/h
    FasmAdd($Fasm, "fmul st0,st5") ;st(0)=i/h
    FasmAdd($Fasm, "fadd st0,st4") ;st(0)=i/h-0.5=dy st1=dx st2=0.39 st3=203.xx st4=-0.5 st5=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;$sqrt=sqrt(dx^2+dy^2)
    FasmAdd($Fasm, "fld st1") ;dx 45
    FasmAdd($Fasm, "fmul st0,st0") ;dx^2
    FasmAdd($Fasm, "fld st1") ;dy
    FasmAdd($Fasm, "fmul st0,st0") ;dy^2
    FasmAdd($Fasm, "faddp st1,st0") ;dx^2+dy^2
    FasmAdd($Fasm, "fsqrt") ;st0=sqrt st1=dy st2=dx

    [/autoit] [autoit][/autoit] [autoit]

    ;dy/(dx+sqrt)
    FasmAdd($Fasm, "fld st0") ;st0=sqrt st1=sqrt st2=dy st3=dx
    FasmAdd($Fasm, "fadd st0,st3") ;st0=sqrt+dx st1=sqrt st2=dy st3=dx
    FasmAdd($Fasm, "fdivr st0,st2") ;st0=y/(sqrt+dx) st1=sqrt st2=dy st3=dx

    [/autoit] [autoit][/autoit] [autoit]

    ;ab hier wird FPATAN() durch einen Zugriff auf die Tabelle ersetzt
    ;an atantabelle[index] steht der atan(index/100), also alle arcustangens von 0 bis 10
    ;index>10
    FasmAdd($Fasm, "fcom dword[zehn]") ;vgl st0 mit zehn (kein platz mehr auf dem stack....)
    FasmAdd($Fasm, "fstsw ax") ;statuswort copro in ax
    FasmAdd($Fasm, "sahf") ;AH ---> prozessorflags
    FasmAdd($Fasm, "jb kleinerzehn") ;wenn größer/gleich +10, dann eax=atantabelle[1000]
    FasmAdd($Fasm, "fstp st0") ;runter vom stack
    FasmAdd($Fasm, "fld [atantabelle+4000]") ;wenn größer/gleich +10, dann 1.4711
    FasmAdd($Fasm, "jmp weiter") ;atan berechnet^^
    ;index<-10
    FasmAdd($Fasm, "kleinerzehn:")
    FasmAdd($Fasm, "fcom dword[minuszehn]") ;vgl st0 mit -zehn (kein platz mehr auf dem stack....)
    FasmAdd($Fasm, "fstsw ax") ;statuswort copro in ax
    FasmAdd($Fasm, "sahf") ;AH ---> prozessorflags
    FasmAdd($Fasm, "ja groessernull") ;wenn >-10 dann groessernull
    FasmAdd($Fasm, "fstp st0") ;runter vom stack
    FasmAdd($Fasm, "fld [atantabelle+4000]") ;wenn größer/gleich +10, dann 1.4711
    FasmAdd($Fasm, "fchs") ;vorzeichen auf minus
    FasmAdd($Fasm, "jae weiter")
    ;index>0
    FasmAdd($Fasm, "groessernull:")
    FasmAdd($Fasm, "fcom dword[null]") ;vgl st0 mit null (kein platz mehr auf dem stack....)
    FasmAdd($Fasm, "fstsw ax") ;statuswort copro in ax
    FasmAdd($Fasm, "sahf") ;AH ---> prozessorflags
    FasmAdd($Fasm, "jbe kleinernull") ;wenn kleiner null, dann kleinernull
    FasmAdd($Fasm, "fimul dword[hundert]") ;st0=100*y/(sqrt+dx) st1=sqrt st2=dy st3=dx
    FasmAdd($Fasm, "fistp [atanindex]") ;runter vom stack
    FasmAdd($Fasm, "fwait") ;
    FasmAdd($Fasm, "mov eax,[atanindex]") ;
    FasmAdd($Fasm, "fld [atantabelle+4*eax]") ;wenn größer/gleich 0, dann atantabelle[index] holen
    FasmAdd($Fasm, "jae weiter")

    [/autoit] [autoit][/autoit] [autoit]

    ;index<0
    FasmAdd($Fasm, "kleinernull:") ;wenn kleiner null
    FasmAdd($Fasm, "fimul dword[hundert]") ;st0=100*y/(sqrt+dx) st1=sqrt st2=dy st3=dx
    FasmAdd($Fasm, "fchs") ;vorzeichen auf plus
    FasmAdd($Fasm, "fistp [atanindex]") ;runter vom stack
    FasmAdd($Fasm, "fwait") ;
    FasmAdd($Fasm, "mov eax,[atanindex]") ;
    FasmAdd($Fasm, "fld [atantabelle+4*eax]") ;atan(index/100)
    FasmAdd($Fasm, "fchs") ;vorzeichen auf minus

    [/autoit] [autoit][/autoit] [autoit]

    ;st0=atan2 , das wars, ca. 50 Zeilen mehr Code, um EINEN Befehl zu ersetzen
    FasmAdd($Fasm, "weiter: ") ;
    ;$tu=int($5div2pi*[ATantabelle+eax]))
    FasmAdd($Fasm, "fmul st0,st5") ;st0=atan2*203 st1=sqrt st2=dy st3=dx
    FasmAdd($Fasm, "fistp [vtu]") ; st0=sqrt st1=dy st2=dx st3=0.39 st4=203.xx st5=-0.5 st6=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;$tv=($nulldrei/sqrt($dx*$dx+$dy*$dy))+$a1
    FasmAdd($Fasm, "fdivr st0,st3 ");st0=0.3/sqrt st1=dy st2=dx st3=0.39 st4=203.xx st5=-0.5 st6=1/h
    FasmAdd($Fasm, "fadd [va1]") ;st0=0.3/sqrt+a1
    FasmAdd($Fasm, "fimul [v256]") ;st0=(0.3/sqrt+a1)*256
    FasmAdd($Fasm, "fistp [vtv]") ;st0=dy st1=dx st3=0.39 st4=203.xx st5=-0.5 st6=1/h
    FasmAdd($Fasm, "fstp st0") ;st0=dx st1=0.39 st2=203.xx st3=-0.5 st4=1/h
    FasmAdd($Fasm, "fstp st0") ;st0=0.39 st1=203.xx st2=-0.5 st3=1/h

    [/autoit] [autoit][/autoit] [autoit]

    ;stack ist in dem zustand, wie er am anfang der schleife war

    [/autoit] [autoit][/autoit] [autoit]

    ;XOR
    FasmAdd($Fasm, "mov eax,[vtu]") ;
    FasmAdd($Fasm, "xor eax,[vtv]") ;
    FasmAdd($Fasm, "and eax,0xFF") ;farbe von RR, GG und BB
    ;pixelfarbe (grauton) erstellen
    FasmAdd($Fasm, "mov ebx,0xFF") ;alpha AA
    FasmAdd($Fasm, "shl ebx,8") ;AA00
    FasmAdd($Fasm, "or ebx,eax") ;AABB
    FasmAdd($Fasm, "shl ebx,8") ;AABB00
    FasmAdd($Fasm, "or ebx,eax") ;AABBGG
    FasmAdd($Fasm, "shl ebx,8") ;AABBGG00
    FasmAdd($Fasm, "or eax,ebx") ;AABBGGRR

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "stosd") ;mov [edi],eax pixel in die bitmap schreiben
    FasmAdd($Fasm, "dec ecx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "mov [vj],ecx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "jnz j_schleife") ;so lange bis 0

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "dec edx") ;schleifenzähler hoehe
    FasmAdd($Fasm, "mov [vi],edx" ) ;schleifenzähler breite
    FasmAdd($Fasm, "jnz i_schleife") ;so lange bis 0

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "ret 16");Programmende

    [/autoit] [autoit][/autoit] [autoit]

    ;variablen,

    [/autoit] [autoit][/autoit] [autoit]

    FasmAdd($Fasm, "nulldrei dd 0.390625") ;100/256
    FasmAdd($Fasm, "zwonulldrei dd 203.718330632686")
    FasmAdd($Fasm, "minuseinhalb dd -0.5")
    FasmAdd($Fasm, "v256 dd 256")
    FasmAdd($Fasm, "hoehe dd 0")
    FasmAdd($Fasm, "breite dd 0")
    FasmAdd($Fasm, "invbreite dd 0.0")
    FasmAdd($Fasm, "va1 dd 0.0")
    FasmAdd($Fasm, "vtu dd 0")
    FasmAdd($Fasm, "vtv dd 0")
    FasmAdd($Fasm, "vi dd 0")
    FasmAdd($Fasm, "vj dd 0")
    FasmAdd($Fasm, "hundert dd 100")
    FasmAdd($Fasm, "null dd 0.0")
    FasmAdd($Fasm, "zehn dd 10.0")
    FasmAdd($Fasm, "minuszehn dd -10.0")
    FasmAdd($Fasm, "atanindex dd 0")
    FasmAdd($Fasm, "atantabelle dd 1000 dup 0") ;array mit 1000 werten für atantabelle[atanindex]=atanvalue erstellen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Binary = FasmGetBinary($Fasm) ;syntaxerror im Assembler abfangen abfangen
    ;~ If @Extended Then ;syntax-error aufgetreten
    ;~ $Error = FasmGetLastError()
    ;~ ConsoleWrite("Error Code:" & $Error[0] & @CRLF & "Error Message:" & $Error[1] & @CRLF & "Error Line:" & $Error[2] & @CRLF)
    ;~ Else ;syntax ok
    ConsoleWrite(String(FasmGetBinary($Fasm)) & @CRLF)
    filedelete("test.bin") ;assembly für externen debugger
    filewrite("test.bin",binarytostring(String(FasmGetBinary($Fasm))))

    [/autoit] [autoit][/autoit] [autoit]

    endfunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe DC und ptr und handle auf die Bitmapdaten
    ;by Andy
    Local $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    Local $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    ;_arraydisplay($adib)
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

    [/autoit]

    /EDIT/ Anbei das äquivalente AutoIt-Script. Was einige vielleicht wundern wird, wieso profitiert AutoIt in keinster Weise von der Optimierung?
    AutoIt ist (Dank an die Entwickler) schon ziemlich nah am Optimum! Der Verwaltungsaufwand für die Interpretation des von uns geschriebenen Scriptes ist so hoch, daß einzelne Optimierungen, die bei einem Compiler sofort wirksam werden, von der Anzahl der dadurch mehr ausgeführten Befehle aufgefressen werden.
    Gerade bei Algorithmen, welche extrem auf einen häufig genutzten "inner Loop" aufbauen, lohnt sich daher die Suche nach Alternativen! Dictionarys oder Listen statt Arrays können ab und zu etwas Schub bringen, das wichtigste ist aber, CODE einzusparen! Jeder Befehl, den AutoIt NICHT interpretieren muss, beschleunigt unser Programm...

    Spoiler anzeigen
    [autoit]

    ;Idea taken from http://js1k.com/demo/462
    ;Ported to AutoIt by UEZ Build 2010-08-20
    #AutoIt3Wrapper_UseUpx=n
    #AutoIt3Wrapper_Run_Obfuscator=y
    #Obfuscator_Parameters=/sf /sv /om /cs=0 /cn=0
    #AutoIt3Wrapper_Run_After=del /f /q "Star Burst_Obfuscated.au3"
    #AutoIt3Wrapper_Run_After=upx.exe --ultra-brute "%out%"
    ;~ #AutoIt3Wrapper_Run_After=upx.exe --best "%out%"
    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    ;Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Local $hGUI, $hGraphics, $hBackbuffer, $hBitmap
    Local $H = 332, $W = 332
    ; Initialize GDI+
    _GDIPlus_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    $hGUI = GUICreate("GDI+ Test", $W, $H)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    $hGraphics = _GDIPlus_GraphicsCreateFromHWND($hGUI)
    $hBitmap = _GDIPlus_BitmapCreateFromGraphics($W, $H, $hGraphics)
    $hBackbuffer = _GDIPlus_ImageGetGraphicsContext($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    ; Using antialiasing
    ;~ _GDIPlus_GraphicsSetSmoothingMode($hBackbuffer, 0)
    ; Create a Brush object
    Local $hBrush = _GDIPlus_BrushCreateSolid()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Dim $atan_array[1000]
    For $i = 0 To 999
    $atan_array[$i] = ATan($i / 100)
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    AdlibRegister("_fps", 1000)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Global $pi = ACos(-1), $pi2 = 2 * $pi, $pi05 = ACos(-1) * 0.5, $fps
    Local $HW = $H * 0.5, $HH = $W * 0.5
    Local $A0 = 0, $A1 = 0, $A2 = 0, $A3 = 0
    Local $ox = 0, $oy = 0, $0z = 0
    Local $tu = 0, $tv = 0
    Local $speed = 2
    Local $i, $j, $x, $y, $o
    Local $cc, $ss, $z, $col
    Local $dx, $dy, $dz, $rd, $A, $B, $C, $R, $t1, $tu, $tv, $q, $g, $l
    Local $d[$W + 1]

    [/autoit] [autoit][/autoit] [autoit]

    $viernullsechs = 203.718330632686 * 2
    $nulldrei = 0.390625
    ;$a1=0.07

    [/autoit] [autoit][/autoit] [autoit]

    While 1;Sleep(10)
    _GDIPlus_GraphicsClear($hBackbuffer, 0xFF000000)

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To $H Step $speed
    For $j = 0 To $W Step $speed
    $dx = ($j / $W) - 0.5;
    $dy = ($i / $H) - 0.5;
    $sqrt = Sqrt($dx * $dx + $dy * $dy)
    $tu = Int($viernullsechs * _atan($dy / ($dx + $sqrt)))
    $tv = ($nulldrei / $sqrt) + $A1
    $tv = Int($tv * 256)
    $g = Hex(BitAND(BitXOR($tu, $tv), 0xFF), 2)
    $col = "0xFF" & $g & $g & $g
    _GDIPlus_BrushSetSolidColor($hBrush, $col)
    _GDIPlus_GraphicsFillRect($hBackbuffer, $j, $i, $speed, $speed, $hBrush)

    [/autoit] [autoit][/autoit] [autoit]

    Next
    Next
    $A1 += 0.07
    ;exit
    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap, 0, 0, $W, $H)
    $fps += 1
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Func _FPS()
    WinSetTitle($hGUI, "", $fps)
    $fps = 0
    EndFunc ;==>_FPS

    [/autoit] [autoit][/autoit] [autoit]

    Func Rotate($t)
    $cc = Cos($t)
    $ss = Sin($t)
    $z = $x * $cc - $y * $ss
    $y = $x * $ss + $y * $cc
    $x = $z
    EndFunc ;==>Rotate

    [/autoit] [autoit][/autoit] [autoit]

    Func _atan($R)
    If $R < 0 Then
    If $R < -9.9 Then Return -1.4711
    Return -$atan_array[Int(Abs($R * 100))]
    Else
    If $R > 9.9 Then Return 1.4711
    Return $atan_array[Int(Abs($R * 100))]
    EndIf
    EndFunc ;==>_atan

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func atan2($y, $x)
    Local $A = (2 * ATan($y / ($x + Sqrt($x * $x + $y * $y))))
    ConsoleWrite($y & " " & $x & " " & $A & @CRLF)
    Return $A
    EndFunc ;==>atan2

    [/autoit] [autoit][/autoit] [autoit]

    Func ATan2_UEZ($y, $x)
    Switch $x
    Case ($x > 0)
    Return ATan($y / $x)
    Case ($x < 0 And $y >= 0)
    Return ATan($y / $x + $pi)
    Case ($x < 0 And $y < 0)
    Return ATan($y / $x - $pi)
    Case ($x = 0 And $y > 0)
    Return $pi05
    Case ($x = 0 And $y < 0)
    Return -$pi05
    Case ($x = 0 And $y = 0)
    Return 0
    EndSwitch
    EndFunc ;==>ATan2_UEZ

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    ; Clean up
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_BitmapDispose($hBitmap)
    _GDIPlus_GraphicsDispose($hBackbuffer)
    _GDIPlus_GraphicsDispose($hGraphics)

    [/autoit] [autoit][/autoit] [autoit]

    ; Uninitialize GDI+
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit]

    ciao
    Andy


    "Schlechtes Benehmen halten die Leute doch nur deswegen für eine Art Vorrecht, weil keiner ihnen aufs Maul haut." Klaus Kinski
    "Hint: Write comments after each line. So you can (better) see what your program does and what it not does. And we can see what you're thinking what your program does and we can point to the missunderstandings." A-Jay

    Wie man Fragen richtig stellt... Tutorial: Wie man Script-Fehler findet und beseitigt...X-Y-Problem

    2 Mal editiert, zuletzt von Andy (27. August 2010 um 09:16)

  • Einsatz von SSE/SSE2 Befehlen am Beispiel Tunnelflug

    Neben MMX und 3DNOW gibt es in den neueren Prozessoren eine ganze Reihe Befehle um SIMD (SingleInstructionMultipleData) anzuwenden. Auch im 32-Bit-Modus können bis zu 8 Register XMM0-XMM7 mit jeweils 128Bit Breite angesprochen werden. Der 64-Bitmodus erweitert die Anzahl der Register noch einmal beträchtlich. Ich verwende die Datenblätter und Manuals von AMD, für interessierte gibts gerade im Bereich Optimierung dort sehr lesenswerte Sachen.
    Als Nachschlagewerk für das vorliegende Programm empfehle ich http://support.amd.com/us/Processor_TechDocs/26568.pdf

    Ich bleibe beim folgenden Beispiel im 32-Bitmodus und verwende dabei einige der SSE/SSE2-Befehle. Das gute an SIMD ist,es werden mit einem Befehl mehrere Daten verändert.
    Ein schönes Beispiel ist PMADDWD, welcher in der Lage ist, 8 Multiplikationen und 4 Additionen auf einmal durchzuführen.

    Was heisst mehrere Befehle auf einmal?
    Nun, wir können ein 128 Bit breites Register in verschiedenen Varianten nutzen, als dqword mit 128 bit, oder als 2er Gruppe mit je 64 Bit, als 4er Gruppe mit je 32 Bit, 8x16Bit, oder 16x8 Bit. Man kann die Registerinhalte als Floatingpoint oder Integer nutzen.
    Ich benutze im vorliegenden Beispiel die XMM-Register als 4x32 Bit. Denn 1 Pixel hat 32 Bit, so kann man 4 Pixel mit einem einzigen Befehl berechnen!
    Das läuft im Prinzip so ab, daß ich die Berechnungen statt mit einem Pixel mit 4en gleichzeitig durchführe.

    Ich habe versucht, so gut wie möglich zu kommentieren, wenn man im oben angegeben AMD-Manual nachschlägt, bekommt man eigentlich eine optimale Darstellung, wie die Register miteinander verwendet werden!
    Ansonsten gilt wie immer, wenn etwas nicht verstanden wurde, nachfragen...

    Ach so...noch etwas zur Geschwindigkeit. Auf meinem Rechner wird der Tunnelflug in 500x500 mit ca.160FPS durchgeführt. Im Vergleich zum Autoit-Script ca. 4300 (viertausendreihundert) mal schneller 8o
    Auf Intel-Prozessoren sollte es noch ein gutes Stück schneller laufen...

    Ich habe die Abfrage nach dem Vorhandensein eines Prozessors mit SSE-Befehlen nicht integriert, auf einem PIII (so einen hab ich auch noch^^) läuft das Script also nicht...

    Spoiler anzeigen
    [autoit]

    #include <FASM.au3>
    #include <MemoryDll.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>
    #include <StructureConstants.au3>
    #include <GDIConstants.au3>
    #include <array.au3>
    #include <GUIConstantsEx.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;Optimierung 1. Teil
    ;im folgenden Beispiel wird der Befehl FPATAN() der ca 300 Takte braucht, durch einen schnellen Zugriff auf eine LookUp-Tabelle LUT ersetzt
    ;der Geschwindigkeitsgewinn beträgt ca. x2!
    ;die lookuptabelle ist ein Array mit dem Index von 0 bis 1000 und enthält die Werte atan(0) bis atan(10)

    [/autoit] [autoit][/autoit] [autoit]

    ;Optimierung 2. Teil
    ;um die Berechnungen noch etwas zu beschleunigen werden 128 Bit breite Register der SSE-Befehlssatzerweiterung angesprochen
    ;damit kann man 4 Pixel auf einmal berechnen. Der Coprozessor wird nur noch genutzt, um per FPATAN die Lookup-Tabelle zu beschreiben

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Opt("GUIOnEventMode", 1)

    [/autoit] [autoit][/autoit] [autoit]

    $b=500 ;Breite und höhe in pixel
    $h=500

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    If $b/4<>int($b/4) then
    msgbox(0,"Information!","Die Breite muss restlos durch 4 teilbar sein, um alignment der Daten zu gewährleisten!")
    $mod=mod($b,4)
    $b=$b+4-$mod
    endif

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    global $Fasm = FasmInit(), $FPS
    _createbytecode() ;assemblercode erstellen

    [/autoit] [autoit][/autoit] [autoit]

    ;backbuffer erstellen für die Bitmap
    local $ptr_bitmap,$hbmp_bitmap ;byref
    $hDC_bitmap=_CreateNewBmp32($b, $h, $ptr_bitmap,$hbmp_bitmap) ;DC, Pointer auf die Bitmapdaten und ein Handle für GDI+....eine eierlegende Wollmilchsau

    [/autoit] [autoit][/autoit] [autoit]

    $hgui=guicreate("",$b,$h,1,1)
    $hdc_gui=_WinAPI_GetDC($hgui)
    guisetstate()

    [/autoit] [autoit][/autoit] [autoit]

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    adlibregister("_fps",1000) ;FramesPerSecond

    [/autoit] [autoit][/autoit] [autoit]

    $step=0.005 ;das ist die Schrittweite, um die der Tunnelflug ein Frame weiter gezeichnet wird

    [/autoit] [autoit][/autoit] [autoit]

    $struct_a=dllstructcreate("float") ;
    dllstructsetdata($struct_a,1,$step) ;zähler, wird nach jedem Frame um $step erhöht

    [/autoit] [autoit][/autoit] [autoit]

    ;$struct_ret=dllstructcreate("float") ;
    ;$struct_ret1=dllstructcreate("dword",DllStructGetPtr($struct_ret)) ;int to float

    [/autoit] [autoit][/autoit] [autoit]

    while 1;sleep(20)
    $Ret = MemoryFuncCall("int", FasmGetFuncPtr($Fasm), "int", $b,"int",$h,"float",dllstructgetdata($struct_a,1),"ptr", $ptr_bitmap)
    _winapi_bitblt($hdc_gui,0,0,$b,$h,$hDC_bitmap,0,0,$srccopy) ;bitmap in die GUI blitten
    $fps+=1
    dllstructsetdata($struct_a,1,dllstructgetdata($struct_a,1)+$step) ;zähler um step erhöhen
    wend

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    func _createbytecode()

    [/autoit] [autoit][/autoit] [autoit]

    FasmReset($Fasm)

    [/autoit] [autoit][/autoit] [autoit]

    _("use32")
    _("org " & FasmGetBasePtr($Fasm))
    _("mov eax,[esp+4]") ;breite
    _("mov [breite],eax") ;
    _("mov [invbreite+0],eax") ;
    _("mov [invbreite+4],eax") ;
    _("mov [invbreite+8],eax") ;
    _("mov [invbreite+12],eax") ;
    _("mov eax,[esp+8]") ;hoehe
    _("mov [hoehe+0],eax") ; 10
    _("mov [hoehe+4],eax") ;
    _("mov [hoehe+8],eax") ;
    _("mov [hoehe+12],eax") ;
    _("mov eax,[esp+12]") ;A1
    _("mov [va1],eax") ;
    _("mov [va1+4],eax") ;
    _("mov [va1+8],eax") ;
    _("mov [va1+12],eax") ;
    _("mov edi,[esp+16]") ;Ptr auf bitmapdaten

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _("FINIT") ;copro init 10
    ;die Tabelle mit Werten füllen
    _("mov ecx,1000") ;tabellenlimit
    _("mov ebx,0") ;zähler tabellenindex
    ;atantabelle[ebx]=ATAN(ebx/100)
    _("_atanschleife:") ;
    _("inc ebx") ;index eins höher
    _("mov dword [atanindex],ebx ") ;index in speicher
    _("fild dword [atanindex]") ;st0=index
    _("fdiv dword[hundert]") ;st0=index/100
    _("fld1") ;st0=1 st1=index/100
    _("fpatan") ; ;st0=atan(st1/st0)
    _("fstp dword[atantabelle+ebx*4]") ;atan im atantabelle[index*4] speichern
    _("cmp ebx, ecx") ;ist limit erreicht?
    _("jne _atanschleife") ;wenn limit noch nicht erreicht, dann nächsten index
    ;lookup-tabelle gefüllt

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _("mov esi,nulldrei") ;4 Konstanten in register packen
    _("movdqa xmm7,[esi+0]") ;nulldrei
    _("movdqa xmm6,[esi+16]") ;viernullsechs
    _("movdqa xmm5,[esi+32]") ;minuseinhalb
    _("movdqa xmm4,[esi+48]") ;breite
    _("cvtdq2ps xmm4,xmm4") ;breite von integer nach float
    _("rcpps xmm4,xmm4") ;invbreite 30

    [/autoit] [autoit][/autoit] [autoit]

    _("mov edx,0");[hoehe]") ;schleifenzähler höhe
    _("i_schleife:") ; for i=0 to h
    _("mov [vi+0],edx") ;
    _("mov [vi+4],edx") ; 40
    ;dy=($i/H)-0.5
    _("movddup xmm3,[esi+160]") ;vi-zähler in register
    _("cvtdq2ps xmm3,xmm3") ;von integer nach float
    _("mulps xmm3,xmm4") ;i/h
    _("addps xmm3,xmm5") ;i/h-0.5
    _("movdqa xmm2,xmm3 ") ;dy
    _("mulps xmm2,xmm2") ;dy^2 50

    [/autoit] [autoit][/autoit] [autoit]

    ;j-schleife
    _("mov ecx,0");[breite]") ;schleifenzähler breite
    _("j_schleife:") ;for j=0 to w
    ;dx=(j/w)-.5
    _("mov [esi+176+0],ecx") ;schleifenzähler in vj
    _("inc ecx") ;
    _("mov [esi+176+4],ecx") ;
    _("inc ecx") ;
    _("mov [esi+176+8],ecx") ;
    _("inc ecx") ;
    _("mov [esi+176+12],ecx") ;

    [/autoit] [autoit][/autoit] [autoit]

    _("movdqa xmm0,[esi+176]") ;vj-zähler
    _("cvtdq2ps xmm0,xmm0") ;von integer nach float
    _("mulps xmm0,xmm4") ;j/w
    _("addps xmm0,xmm5") ;(j/w)-0.5
    _("movdqa xmm1,xmm0") ;dx
    _("mulps xmm1,xmm1") ;dx^2
    _("addps xmm1,xmm2") ;dx^2+dy^2
    _("sqrtps xmm1,xmm1") ;sqrt
    ;dy/(dx+sqrt)
    _("addps xmm0,xmm1") ;dx+sqrt 60
    _("divps xmm0,xmm3") ;(dx+sqrt)/dy
    _("rcpps xmm0,xmm0") ;dy/(dx+sqrt)
    _("mulps xmm0,[esi+192]") ;*100
    _("cvtps2dq xmm0,xmm0") ;convert to integer (das sind die indizes!)
    _("movdqa [esi+256],xmm0") ;indizes in atanindex
    _("call _indextoatan") ;
    ;im atanindex stehen nun die atan-werte

    [/autoit] [autoit][/autoit] [autoit]

    _("movdqa xmm0,[esi+256]") ;4 atans in xmm0
    ;tu=int(407.xxx * atan)
    _("mulps xmm1,xmm7") ;sqrt/0.3
    _("mulps xmm0,xmm6") ;atan * 407

    [/autoit] [autoit][/autoit] [autoit]

    ;tv=(nulldrei / sqrt) +A1

    [/autoit] [autoit][/autoit] [autoit]

    _("rcpps xmm1,xmm1") ;0.3/sqrt
    _("cvtps2dq xmm0,xmm0") ;convert to integer (das ist tu)
    _("addps xmm1,[esi+112]") ;(0.3/sqrt)+A1
    _("mulps xmm1,[esi+64]") ;*256
    _("cvtps2dq xmm1,xmm1") ;convert to integer (das ist tv)
    _("pxor xmm1,xmm0") ;xor tu,tv
    _("pand xmm1,[esi+208]") ;and 255
    _("movdqa xmm0,xmm1") ;00 00 00 FE die Farbe

    [/autoit] [autoit][/autoit] [autoit]

    ;"Pixel erzeugen" AABBGGRR aus 000000FE soll FFFEFEFE werden
    _("movdqa xmm0,[esi+208]") ;or 00 00 00 FF Alphakanal
    _("pslldq xmm0,1") ;1 byte nach links 00 00 FF 00
    _("por xmm0,xmm1") ;or 00 00 FF FE
    _("pslldq xmm0,1") ;1 byte nach links 00 FF FE 00
    _("por xmm0,xmm1") ;or 00 FF FE FE
    _("pslldq xmm0,1") ;1 byte nach links FF FE FE 00
    _("por xmm0,xmm1") ;or FF FE FE FE

    [/autoit] [autoit][/autoit] [autoit]

    _("movdqa [edi],xmm0") ;4 Pixel in bitmap
    _("add edi,16") ;4 pixel weiter
    _("add ecx,1") ;4 Pixel weiter
    _("cmp ecx,[breite]") ;zeile ausgefüllt?
    _("jl j_schleife") ;
    _("inc edx") ;eine zeile weiter
    _("cmp edx,[hoehe]") ;alle pixel gezeichnet?
    _("jb i_schleife") ;ansonsten nächste zeile
    _("ret 16") ;Programm ende

    [/autoit] [autoit][/autoit] [autoit]

    ;*****FUNKTION, MIT CALL ANGESPRUNGEN*****************************
    ;index in atan umwandeln
    _("_indextoatan:") ;index
    _("") ;
    _("mov eax,-1") ;eax ist der zähler der indizes
    _("_naechsterindex:") ;
    _("inc eax") ;eax=eax+1
    _("mov ebx,[atanindex+eax*4]") ;index holen
    ; _("mov ebx,-30") ;zurück zum call
    ;>1000
    _("cmp ebx,1000") ;index>1000?
    _("jl kleinerminustausend") ;
    _("mov ebx,[atantabelle+4000]") ;größter index
    _("mov [atanindex+eax*4],ebx") ;float nach atanindex
    _("jmp weiter") ;
    ;<-1000
    _("kleinerminustausend:") ;
    _("cmp ebx,-1000") ;
    _("jg groessernull") ;
    _("fld [atantabelle+4000]") ;größter index
    _("fchs") ;vorzeichen auf minus
    _("fstp [atanindex+eax*4]") ;float nach atanindex
    _("jmp weiter") ;
    ;>0
    _("groessernull:") ;
    _("cmp ebx,0") ;
    _("jle kleinernull") ;
    _("mov ebx,[atantabelle+4*ebx]") ;index
    _("mov [atanindex+eax*4],ebx") ;float nach atanindex
    _("jmp weiter") ;
    ;<0
    _("kleinernull:") ;
    _("neg ebx") ;vorzeichen auf plus
    _("fld [atantabelle+4*ebx]") ;index holen
    _("fchs") ;vorzeichen auf minus
    _("fstp [atanindex+eax*4]") ;float nach atanindex
    _("") ;
    _("weiter:") ;
    ;_("ret") ;zurück zum call
    _("cmp eax,3") ;
    _("jb _naechsterindex") ;nächster index
    _("ret") ;zurück zum call
    ;*********************ENDE FUNKTION****************

    [/autoit] [autoit][/autoit] [autoit]

    ;Variablen und Konstanten
    _("align 16") ;ausrichten für sse
    _("nulldrei dd 4 dup 2.56") ;100/256 ;esi+0
    _("viernullsechs dd 4 dup 407.436661265372") ;esi+16
    _("minuseinhalb dd 4 dup -0.5") ;esi+32
    _("invbreite dd 4 dup 0.0") ;esi+48
    _("v256 dd 4 dup 256.0") ;esi+64
    _("hoehe dd 4 dup 0") ;esi+80
    _("breite dd 4 dup 0") ;esi+96
    _("va1 dd 4 dup 0.0") ;esi+112
    _("vtu dd 4 dup 0") ;esi+128
    _("vtv dd 4 dup 0") ;esi+144
    _("vi dd 4 dup 0") ;esi+160
    _("vj dd 4 dup 0") ;esi+176
    _("hundert dd 4 dup 100.0") ;esi+192
    _("i255 dd 4 dup 0xFF") ;esi+208
    _("zehn dd 4 dup 10.0") ;esi+224
    _("minuszehn dd 4 dup -10.0") ;esi+240
    _("atanindex dd 4 dup 0") ;esi+256
    _("atantabelle dd 1000 dup 0") ;array mit 1000 werten für atantabelle[atanindex]=atanvalue erstellen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Binary = FasmGetBinary($Fasm) ;syntaxerror im Assembler abfangen abfangen
    ;~ If @Extended Then ;syntax-error aufgetreten
    ;~ $Error = FasmGetLastError()
    ;~ ConsoleWrite("Error Code:" & $Error[0] & @CRLF & "Error Message:" & $Error[1] & @CRLF & "Error Line:" & $Error[2] & @CRLF)
    ;~ Else ;syntax ok
    ConsoleWrite(String(FasmGetBinary($Fasm)) & @CRLF)
    filedelete("test.bin") ;assembly für externen debugger
    filewrite("test.bin",binarytostring(String(FasmGetBinary($Fasm))))

    [/autoit] [autoit][/autoit] [autoit]

    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    func _fps()
    winsettitle($hgui,"",$fps&" FPS")
    $fps=0
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Exit()
    Exit
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _($str) ; Nur für die bequemlichkeit ^^
    FasmAdd($Fasm, $str)
    EndFunc ;==>f

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe DC und ptr und handle auf die Bitmapdaten
    ;by Andy
    Local $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    Local $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    Local $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', $DIB_RGB_COLORS, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    ;_arraydisplay($adib)
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

    [/autoit]
  • Beispiel für Übergabe und Rückgabe von Parametern an/von einer AutoItfunktion aus dem Assemblercode

    Anbei ein Beispiel, wie man aus dem Assembler sehr einfach AutoIt-Funktionen aufrufen kann, und natürlich auch die Rückgabe dieser Funktionen auswerten kann.
    Das kann man u.a. natürlich sehr schön zum Debuggen des Assemblercodes verwenden!
    Falls man Werte/Registerinhalte innerhalb des Assemblercodes überprüfen möchte, ist das eine sehr einfache Möglichkeit!

    Spoiler anzeigen
    [autoit]

    #include <FASM.au3>
    #include <Array.au3>
    #include <MemoryDll.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;Beispiel für Übergabe und Rückgabe von Parametern an und von AutoIt-Funktionen

    [/autoit] [autoit][/autoit] [autoit]

    ;AutoItfunktion erstellen, 3 Parameter
    func _Testfunc($integer,$float,$string)
    msgbox(0,"Parameter aus dem Assemblercode", _
    "Integer: "&$integer&@crlf& _ ;INTEGER
    "Float: "&$float&@crlf& _ ;FLOAT
    "Text: "&$string&@crlf ) ;String
    return 66 ;Rückgabewert an das Assemblerprogramm
    endfunc

    [/autoit] [autoit][/autoit] [autoit]

    ;Callback-Adresse festlegen
    ;Reihenfolge der Funktionsparameter wie bei der AutoIt-Funktion
    $Func = DllCallbackRegister("_Testfunc", "int","int;float;str")

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Dim $Fasm = FasmInit()
    FasmReset($Fasm)
    _("use32")
    _("org " & FasmGetBasePtr($Fasm))
    _("mov eax,44") ;Integer belegen
    ;Parameter an die AutoItfunktion auf den Stack pushen!
    ;Beachten, daß LIFO, der zuerst gepushte Parameter ist der letzte der Funktion!
    _("push _teststring") ;dritter Parameter der AutoIt-Testfunc bei Strings nur die Adresse!
    _("push [_float]") ;zweiter Parameter der AutoIt-Testfunc ansonsten den INHALT der Variablen
    _("push eax") ;erster Parameter der AutoIt-Testfunc
    _("call " & DllCallbackGetPtr($Func))
    ;der call bereinigt den Stack, daher KEINESFALLS POPen!
    _("shr eax, 1") ;rückgabe aus dem call in EAX shiftright 1 = geteilt durch 2
    _("ret")
    ;variablen
    _("_float dd 3.1415926")
    _("_teststring db 'Hallo, das ist ein Text',0")

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(String(FasmGetBinary($Fasm)) & @CRLF)
    $Ret = MemoryFuncCall("int", FasmGetFuncPtr($Fasm))
    msgbox(0,"Rückgabe aus der AutoItfunktion","EAX / 2 = "&$ret[0])

    [/autoit] [autoit][/autoit] [autoit]

    DllCallbackFree($Func) ;Funktion freigeben
    FasmExit($Fasm)

    [/autoit] [autoit][/autoit] [autoit]

    Func _($str) ; Nur für die bequemlichkeit ^^
    Fasmadd($Fasm,$str)
    EndFunc ;==>f
    exit

    [/autoit]
  • Hi,
    siehe EDIT im Startpost zu "AssembleIt", vereinfacht ggf einiges^^

  • Beispiel um aus einer Assemblerfunktion eine DLL zu machen

    Wenn man erfolgreich eine Funktion in Assembler erstellt hat, und diese Funktion auch anderen zur Verfügung stellen möchte, bietet sich eine DLL an.
    Somit kann eure Funktion auch von Leuten genutzt werden, die nicht in AutoIt programmieren....

    Ich habe folgende kleine Funktion, um aus farbigen Bildern Graustufenbilder zu erstellen.

    Spoiler anzeigen
    [autoit]

    #include <AssembleIt.au3>
    #include <Array.au3>
    #include <GDIPlus.au3>
    #include <ScreenCapture.au3>

    [/autoit] [autoit][/autoit] [autoit]

    ;grau = (RR + GG + BB) / 3
    func _graustufen()
    _("use32") ;sollte immer eingesetzt werden!

    [/autoit] [autoit][/autoit] [autoit]

    _("mov esi,dword[esp+4]") ;Startadresse Bitmapdaten (Pixel)
    _("mov ecx,dword[esp+8]") ;anzahl Pixel
    _("mov edi,21845") ;konstante, *21845/2^16 ist ungefähr 1/3
    _("_schleife:") ;so lange, bis ecx=0
    _("mov edx,[esi]") ;pixel laden AARRGGBB (RR+GG+BB)/3 =farbe graustufe
    _("mov al,dl") ;lowbyte (BB) vom Pixel nach lowbyte al
    _("movzx bx,dh") ;highbyte (GG) vom Pixel nach lowbyte von bx (bh ist 0)
    _("shr edx,8") ;RR ins dh schieben
    _("add ax,bx") ;BB + GG
    _("movzx bx,dh") ;highbyte (RR) vom Pixel nach lowbyte von bx (bh ist 0)
    _("add ax,bx") ;und dazuzählen dx=RR+GG+BB
    _("mul edi") ;*21845 *21845/2^16 ist ungefähr 1/3
    _("shr eax,16") ;/2^16 in al steht nun der farbcode (grauton) für RR, GG und BB
    _("movzx dx,al") ;grauton nach dl, in dh steht 0
    _("shl edx,16") ;grauton nach RR, in AA steht 0!
    _("mov dh,al") ;grauton nach GG
    _("mov dl,al") ;grauton nach BB In edx steht nun 00alalal=grauton
    _("mov [esi],edx") ;pixel schreiben
    _("add esi,4") ;nächstes Pixel(32 Bit = 4 Byte)
    _("loop _schleife") ;ecx=ecx-1 , so lange zu _schleife springen, bis ecx=0
    _("ret 8") ;ACHTUNG, in der neuesten ASSEMBLEIT nur noch RET, ohne die 8 !
    endfunc

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()
    _ScreenCapture_Capture(@ScriptDir&"\testfile.jpg",0,0,@DesktopWidth,@DesktopHeight)
    $hBitmap=_GDIPlus_ImageLoadFromFile(@ScriptDir&"\testfile.jpg")

    [/autoit] [autoit][/autoit] [autoit]

    Local $iWidth, $iHeight, $hBitmapData, $Scan, $Stride, $tPixelData, $pPixelStruct
    $iWidth = _GDIPlus_ImageGetWidth($hBitmap)
    $iHeight = _GDIPlus_ImageGetHeight($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    ;Pointer auf die Pixel ermitteln
    $hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
    $Scan = DllStructGetData($hBitmapData, "Scan0")
    $Stride = DllStructGetData($hBitmapData, "Stride")
    $tPixelData = DllStructCreate("dword[" & (Abs($Stride * $iHeight)) & "]", $Scan) ;struct enthält die Bitmap (Pixel)

    [/autoit] [autoit][/autoit] [autoit]

    ;farben --> grautöne
    $ret=_AssembleIt("ptr","_graustufen","ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight) ;

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
    _GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\testfile_grau.jpg")

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute(@ScriptDir & "\testfile_grau.jpg")

    [/autoit]


    Aus dem Assemblerteil soll eine DLL erstellt werden.

    Hier das Grundgerüst einer DLL, in eurem FASM-Ordner existiert eine Datei FASMW.EXE, das ist die FASM-IDE. Starten und den folgenden Code in den FASMW-Editor kopieren. Nach einem CTRL+F9 (Run;Compile) wird die DLL erstellt.
    Ich werde die einzelnen Zeilen des folgenden Codes hier nicht weiter kommentieren, wer sich über die Eingeweide von DLL´s informieren möchte kann gerne die Suchmaschine seiner Wahl benutzen, oder Fragen im Assembler-Fragethread stellen!

    Spoiler anzeigen
    [autoit]

    ; DLL creation example
    ;
    ;1) Funktion erstellen in der section .text
    ; proc Funktionsname
    ; AssemblerCode....wie er in AutoIt lauffähig ist... hierhinkopieren
    ; endp
    ;
    ;2) In die section .edata den Funktionsnamen eintragen:
    ;export 'DLLNAME.DLL',\ ;Name der DLL-Datei
    ;Funktionsname1,'Funktionsname1',\ ;Funktionsnamen
    ;Funktionsname2,'Funktionsname2'
    ;
    ;3) *.asm-datei mit wfasm.exe oder fasm.exe compilieren (in FASMW.EXE laden und CTRL+F9 drücken)
    ;
    ;Aufruf aus AutoIt mit
    ;$ret=dllcall("dllname.dll","RückgabeTYP","Funktionsname","TYP",$parameter1)

    [/autoit] [autoit][/autoit] [autoit]

    format PE GUI 4.0 DLL
    entry DllEntryPoint

    [/autoit] [autoit][/autoit] [autoit]

    include 'win32ax.inc' ;includes

    [/autoit] [autoit][/autoit] [autoit]

    ;einzubindende Librarys
    section '.idata' import data readable writeable
    library kernel,'KERNEL32.DLL',\
    user,'USER32.DLL'

    [/autoit] [autoit][/autoit] [autoit]

    ;************Hier die in der DLL verwendeten Funktionen für den Export eintragen
    section '.edata' export data readable
    export 'TESTDLL.DLL',\ ;Dateiname, Zeilentrenner ist ,\
    TestFunc,'TestFunc',\ ;Funktion
    AddTwoInt,'AddTwoInt',\ ;Funktion
    Graustufen,'Graustufen' ;letzte Funktion ohne das ,\

    [/autoit] [autoit][/autoit] [autoit]

    ;weitere Sektionen je nach Anforderung der Funktionen
    section '.data' data readable writeable

    [/autoit] [autoit][/autoit] [autoit]

    _var1 dd ? ;irgendwelche Variablen, wie sie in den Funktionen verwendet werden
    _var2 db ?
    _sechsundsechzig = 66 ;konstante

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;section für die Funktionen
    section '.code' code readable executable

    [/autoit] [autoit][/autoit] [autoit]

    ;DllEntryPoint wird beim Laden der DLL aufgerufen
    ;um "bombensicheres" Errorhandling zu haben, Funktion anpassen!
    proc DllEntryPoint hinstDLL,fdwReason,lpvReserved
    mov eax,TRUE ;hart aber herzlich^^
    ret
    endp

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;******************Ab hier fangen die Benutzer-Funktionen an **********

    [/autoit] [autoit][/autoit] [autoit]

    proc Graustufen
    ;ab hier folgt der Code, wie er z.B. von AssembleIt verarbeitet wird
    use32
    mov esi,dword[esp+4] ;Startadresse Bitmapdaten (Pixel)
    mov ecx,dword[esp+8] ;anzahl Pixel
    mov edi,21845 ;konstante, *21845/2^16 ist ungefähr 1/3
    _schleife: ;so lange, bis ecx=0
    mov edx,[esi] ;pixel laden AARRGGBB (RR+GG+BB)/3 =farbe graustufe
    mov al,dl ;lowbyte (BB) vom Pixel nach lowbyte al
    movzx bx,dh ;highbyte (GG) vom Pixel nach lowbyte von bx (bh ist 0)
    shr edx,8 ;RR ins dh schieben
    add ax,bx ;BB + GG
    movzx bx,dh ;highbyte (RR) vom Pixel nach lowbyte von bx (bh ist 0)
    add ax,bx ;und dazuzählen dx=RR+GG+BB
    mul edi ;*21845 *21845/2^16 ist ungefähr 1/3
    shr eax,16 ;/2^16 in al steht nun der farbcode (grauton) für RR, GG und BB
    movzx dx,al ;grauton nach dl, in dh steht 0
    shl edx,16 ;grauton nach RR, in AA steht 0!
    mov dh,al ;grauton nach GG
    mov dl,al ;grauton nach BB In edx steht nun 00alalal=grauton
    mov [esi],edx ;pixel schreiben
    add esi,4 ;ein Pixel = 32Bit = 4Byte weiter
    loop _schleife ;ecx=ecx-1 , springe so lange nach _schleife, bis ecx=0
    ret 8
    endp

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;eine weitere Funktion gibt die eingegebene Zahl einfach zurück
    proc TestFunc Zahl:DWORD
    mov eax,dword[Zahl]
    leave ;nötig, wenn ebp nicht verwendet wird (pop ebp to esp)
    retn 4
    endp

    [/autoit] [autoit][/autoit] [autoit]

    ;und noch eine Funktion addiert zwei Integer....
    proc AddTwoInt Zahl1:DWORD ,Zahl2:DWORD
    mov eax,dword[Zahl1]
    mov ebx,dword[Zahl2]
    add eax,ebx
    leave
    retn 8
    endp

    [/autoit] [autoit][/autoit] [autoit]

    section '.reloc' fixups data discardable

    [/autoit]

    Im Prinzip besteht die "Arbeit", einen Funktionsnamen zu erstellen und den Assemblercode zwischen proc/endp zu kopieren, und den Funktionsnamen in die Section .edata einzutragen.
    /EDIT/ Das gilt natürlich nur für relativ "einfache" Funktionen. Wer mit AutoIt-DllCallbacks() und weiteren Spezialitäten in seinem Assemblercode arbeitet, muß sich Gedanken machen, wie diese Adressen in die Dll-Funktionen kommen.

    Die größte "Arbeit" ist, die _(" und die ") um die eigentlichen Assemblerbefehle herum zu löschen^^, aber wozu gibt es AutoIt, damit kann man sich ein Script erstellen, so daß auf Knopfdruck der "bereinigte" Code in der Zwischenablage steht und nur noch per CTRL+V eingefügt werden muss...

    Nachdem die DLL erstellt wurde, kann man nun aus AutoIt folgendermassen die Funktionen in der DLL aufrufen:

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <ScreenCapture.au3>

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $testdll=dllopen("testdll.dll")

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()
    _ScreenCapture_Capture(@ScriptDir&"\testfile.jpg",0,0,@DesktopWidth,@DesktopHeight)
    $hBitmap=_GDIPlus_ImageLoadFromFile(@ScriptDir&"\testfile.jpg")

    [/autoit] [autoit][/autoit] [autoit]

    Local $iWidth, $iHeight, $hBitmapData, $Scan, $Stride, $tPixelData, $pPixelStruct
    $iWidth = _GDIPlus_ImageGetWidth($hBitmap)
    $iHeight = _GDIPlus_ImageGetHeight($hBitmap)

    [/autoit] [autoit][/autoit] [autoit]

    $hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
    $Scan = DllStructGetData($hBitmapData, "Scan0")
    $Stride = DllStructGetData($hBitmapData, "Stride")
    $tPixelData = DllStructCreate("dword[" & (Abs($Stride * $iHeight)) & "]", $Scan)

    [/autoit] [autoit][/autoit] [autoit]

    ;DLL-Call für die Graustufenfunktion
    $ret= DllCall("testdll.dll", "ptr", "Graustufen","ptr", DllStructGetPtr($tPixelData), "int", $iWidth * $iHeight)
    ;Dll-Call für die AddTwoInt()Funktion
    $ret= DllCall("testdll.dll", "int", "AddTwoInt","int", 33333, "int", 44444);bytecode aufrufen, rückgabe in a[0]
    Consolewrite("AddTwoInt() = "&$ret[0]&@crlf)

    [/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
    _GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\testfile_grau.jpg")

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute(@ScriptDir & "\testfile_grau.jpg")

    [/autoit]


    Und die Dll, wie sie von FASM erstellt wurde...autoit.de/wcf/attachment/11318/

    /EDIT/ Wenn man die Dll disassembliert wird man sehen, daß FASM "eigenständig" den Base- und Stackpointer rettet und auch dementsprechend die richtigen Rücksprungadressen ermittelt. Auf die hier gezeigte Art und Weise (per in AutoIt eingebettetem FASM) wird man keine "großen" Dll's erstellen, dafür sind dann "richtige" Assembler (FASM, FASMW) wesentlich besser geeignet! Dort hat man mit den Bibliotheken vollen und sehr einfachen Zugriff auf u.a. die WinAPI-Funktionen, Macros und vieles mehr.
    Bei den von mir getesteten Windowsversionen (XP,Vista,Win7 alles 32Bit) hat es auch nichts ausgemacht, die alphabetische Reihenfolge der Funktionsnamen in der Dll durcheinanderzuwürfeln.

  • Hallo Andy,

    Ich habe grade versucht eine Funktion in eine DLL zu exportieren, aber bekomme von FASMW.exe den Fehler "Invalid Use of Symbol".

    Ich habe 2 eigene Variablen im Code, und benutze infolgedessen esi+variable um sie anzusprechen.

    "mov eax,dword[esi+_iFound]"

    Wie kann ich das ganze nun so umbauen, dass es funktioniert?

  • Hi,
    da hast du mich schön kalt aus der Hüfte erwischt^^

    ich hatte im obigen Beispiel einen kleinen Fehler eingebaut, der aber dort nicht aufgefallen ist...
    Die Zeile

    Code
    section '.reloc' fixups data discardable

    gehört idR in die letzte Zeile, damit wird der Speicher "geputzt"

    Zu deiner Frage:
    Erstelle eine section .data

    Code
    section '.data' data readable writeable
    
    
    _var1 dd ?    ;irgendwelche Variablen, wie sie in den Funktionen verwendet werden
    _var2 db ?
    _sechsundsechzig = 66  ;konstante

    jetzt kannst du per mov eax,dword[_var1] auf deine Variable zugreifen. Die Variante [esi+_var1] hatten wir ja nur verwendet, um den "AutoIt-Assembler" auf unsere Variablen umzubiegen, die Dll wird beim Laden so umgeschrieben, daß die Adressen "passen"

  • Verwendung von AutoIt-Variablen im Assemblercode

    Hi,
    was ich noch garnicht vorgestellt hatte ist "mixed Code", indem man AutoItvariablen bzw auch Funktionen direkt in den Assemblercode einsetzt!
    Solange einem die Geschwindigkeit von _AssembleIt() reicht, braucht man sich so nicht mal um die Übergabeparameter bzw den Stack Gedanken zu machen!
    Der Aufruf des Assemblers gestaltet sich dann einfach so:

    [autoit]

    $ret=_AssembleIt("RückgabeTyp","Funktionsname_in_dem_der_Assemblercode_steht")

    [/autoit]

    Wie man AutoIt-Variablen im Assemblercode verwendet sieht man hier:

    Spoiler anzeigen
    [autoit]

    #include <AssembleIt.au3>
    #include <GDIPlus.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $Scan, $iWidth, $iHeight ;in der assemblerfunc verwendete Variablen deklarieren
    Global $ASM_VAR_pointer1, $ASM_VAR_pointer2 ;Variable, der ein Registerinhalt zugewiesen wird

    [/autoit] [autoit][/autoit] [autoit]

    Func _graustufen()
    _("use32") ;sollte immer eingesetzt werden!

    [/autoit] [autoit][/autoit] [autoit]

    _("mov esi," & $Scan) ;Startadresse Bitmapdaten (Pixel)
    _("mov ecx," & $iWidth * $iHeight) ;anzahl Pixel
    _("mov edi,21845") ;konstante, *21845/2^16 ist ungefähr 1/3

    [/autoit] [autoit][/autoit] [autoit]

    _("_schleife:") ;so lange, bis ecx=0
    _("mov edx,[esi]") ;pixel laden AARRGGBB (RR+GG+BB)/3 =farbe graustufe
    _("mov al,dl") ;lowbyte (BB) vom Pixel nach lowbyte al
    _("movzx bx,dh") ;highbyte (GG) vom Pixel nach lowbyte von bx (bh ist 0)
    _("shr edx,8") ;RR ins dh schieben
    _("add ax,bx") ;BB + GG
    _("movzx bx,dh") ;highbyte (RR) vom Pixel nach lowbyte von bx (bh ist 0)
    _("add ax,bx") ;und dazuzählen dx=RR+GG+BB
    _("imul edi") ;*21845 *21845/2^16 ist ungefähr 1/3
    _("shr eax,16") ;/2^16 in al steht nun der farbcode (grauton) für RR, GG und BB
    _("movzx dx,al") ;grauton nach dl, in dh steht 0
    _("shl edx,16") ;grauton nach RR, in AA steht 0!
    _("mov dh,al") ;grauton nach GG
    _("mov dl,al") ;grauton nach BB In edx steht nun 00alalal=grauton
    _("mov [esi],edx") ;pixel schreiben

    [/autoit] [autoit][/autoit] [autoit]

    _("add esi,4") ;3x4
    _("sub ecx,1") ;3 pixel pro schleifendurchgang
    _("ja _schleife") ;so lange, bis ecx=0
    ;wesentlich schneller als _("loop _schleife") ;so lange, bis ecx=0
    _("mov [" & $ASM_VAR_pointer1 & "],esi") ;Register in Variable schreiben
    _("mov [" & $ASM_VAR_pointer2 & "],edx") ;Register in Variable schreiben
    _("ret ")
    EndFunc ;==>_graustufen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_Startup()
    $file = FileOpenDialog("24 oder 32 Bpp auswählen", @ScriptDir, "Bilder (*.jpg;*.bmp)", 1 + 2)
    If @error Then Exit
    $hBitmap = _GDIPlus_BitmapCreateFromFile($file)

    [/autoit] [autoit][/autoit] [autoit]

    Local $iWidth, $iHeight, $hBitmapData, $Scan, $Stride, $tPixelData, $pPixelStruct
    $iWidth = _GDIPlus_ImageGetWidth($hBitmap)
    $iHeight = _GDIPlus_ImageGetHeight($hBitmap)
    $hBitmapData = _GDIPlus_BitmapLockBits($hBitmap, 0, 0, $iWidth, $iHeight, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32RGB)
    $Scan = DllStructGetData($hBitmapData, "Scan0") ;Startadresse der Bitmapdaten

    [/autoit] [autoit][/autoit] [autoit]

    ;****************struct für die AutoItVariable erstellen und pointer zuweisen************
    $ASM_VAR_Struct = DllStructCreate("int Variable1;int Variable2")
    $ASM_VAR_pointer1 = DllStructGetPtr($ASM_VAR_Struct, "Variable1")
    $ASM_VAR_pointer2 = DllStructGetPtr($ASM_VAR_Struct, "Variable2")
    ;****************************************************************************************

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $ret = _AssembleIt("ptr", "_graustufen")
    MsgBox(0, "Inhalt Register", "Register ESI = " & DllStructGetData($ASM_VAR_Struct,"Variable1"))
    MsgBox(0, "Inhalt Register", "Register EBX = " & hex(DllStructGetData($ASM_VAR_Struct,"Variable2")))

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _GDIPlus_BitmapUnlockBits($hBitmap, $hBitmapData)
    _GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\graustufen.bmp")

    [/autoit] [autoit][/autoit] [autoit]

    ShellExecute(@ScriptDir & "\graustufen.bmp")
    FasmExit($Fasm) ;FASM aus dem Speicher entfernen

    [/autoit]

    Leider unterstützt AutoIt keine Pointer auf die Variablen, somit muss man, wenn man Registerinhalte in eine AutoIt-Variable schreiben möchte, den Umweg über eine DllStruct() nehmen.
    Das ist eine SEHR feine Methode, um Registerinhalte während der Laufzeit auszulesen. Ich hatte ja schon die Möglichkeit angesprochen, per Callback() AutoItfunktionen aus dem Assembler heraus aufzurufen!
    So kann man mittels Debug-Messageboxen oder auch Consolewrites die Funktion des Assemblercodes tracen/debuggen.

    Wer mag, kann natürlich auch Registerinhalte während der Laufzeit auf diese Art ändern^^

  • Hi,
    wer sich etwas näher mit Assembler befasst hat und jetzt dabei ist seinen Code aufzumotzen, der wird sicher bei einemBlick hierrauf, sicher gemerkt haben das ein DIV ziemlich lange braucht (etwa 70 Takte). Das kann man aber Gott sei Dank um den Faktor 35 verschnellern.
    Agner Fog hat hier (16.9) eine sehr schöne Anleitung geschrieben.

    Und damit mann aber nicht jedes mal Taschenrechner, Zettel und Papier raushohen muss hab ich eine kleine Hilfe gebaut ;).
    Es wird die maximal Dividierbare Zahl ausgegeben die ohne Überlauf geteilt werden kann mit der Methode.
    Außerdem fertiger Assembler und C++ Code

    Hier mal ein Beispiel

    Eine Division durch 10 ist also

    Divident * 52429 & 19 Bits nach rechts shiften

    50 * 52429 = 2621450
    10 1000 0000 0000 0000 1010 (2621450)
    00 0000 0000 0000 0000 0101 <--19 Bits nach rechts geshiftet

    101 ist 5 stimmt also 8) .
    und das alles nur mit 2 Takten 8o.

    Wenn man nicht allzu verschiedene Werte teilen muss brauch man sich nur eine Array anlegen.
    Ist der Bereich zu groß wird sollte mann doch lieber bei DIV bleiben. Wer will schon 2mb Assemblercodes ;) .