Delphi-PRAXiS
Seite 1 von 3  1 23      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Assembler in Delphi! Speichersack? (https://www.delphipraxis.net/9620-assembler-delphi-speichersack.html)

neolithos 30. Sep 2003 11:17


Assembler in Delphi! Speichersack?
 
Ich habe zur Übung ein Stück Quell-Code in Assembler umgewandelt.

Delphi-Quellcode:
function TColorPalette.HitColorText(apt: TPoint): Integer;
var x : Integer;
{begin
  if PtInRect(ClientRect, apt) then
     if ((apt.x mod 17) > 14) or ((apt.y mod 17) > 14) then
        Result := -1
     else
        Result := (apt.x div 17) + (apt.y div 17) * 8
  else
     Result := -1;
end;}
asm
  // apt.x div 17
  mov eax, apt.x
  mov ecx, 17
  push edx
  mov edx, 0
  div ecx
  cmp edx, 14
  jns @nowhere
  mov x, eax
  // apt.y div 17
  pop edx
  mov eax, apt.y
  mov edx, 0
  div ecx
  cmp edx, 14
  jns @nowhere
  // Result := x + y(eax) * 8
  shl eax, 3
  or eax, x
  cmp eax, 40
  jns @nowhere
  mov @Result, eax
  jmp @1
@nowhere:
  mov @Result, -1 // Result := -1
@1:
end;
Leider gibt es an einer anderen stelle im Programm ein Speicherproblem.
Wo mach ich was, was ich nicht darf?

sakura 30. Sep 2003 11:23

Re: Assembler in Delphi! Speichersack?
 
Das Ergebnis wird für Integer-Funktionen in EAX zurückgegeben, ansonsten kannst Du natürlich auch Result ansprechen, allerdings ohne die @ Operatoren ;-)

Code:
function TColorPalette.HitColorText(apt: TPoint): Integer;
var x : Integer;
{begin
  if PtInRect(ClientRect, apt) then
     if ((apt.x mod 17) > 14) or ((apt.y mod 17) > 14) then
        Result := -1
     else
        Result := (apt.x div 17) + (apt.y div 17) * 8
  else
     Result := -1;
end;}
asm
  // apt.x div 17
  mov eax, apt.x
  mov ecx, 17
  push edx
  mov edx, 0
  div ecx
  cmp edx, 14
  jns @nowhere
  mov x, eax
  // apt.y div 17
  pop edx
  mov eax, apt.y
  mov edx, 0
  div ecx
  cmp edx, 14
  jns @nowhere
  // Result := x + y(eax) * 8
  shl eax, 3
  or eax, x
  cmp eax, 40
  jns @nowhere
[color=#ff0000][s] mov @Result, eax[/s][/color]
  jmp @1
@nowhere:
  mov [color=#ff001b]EAX[/color], -1 // Result := -1
@1:
end;
...:cat:...

neolithos 30. Sep 2003 11:31

Re: Assembler in Delphi! Speichersack?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nach Änderung entsteht folgender Fehler...

negaH 30. Sep 2003 11:41

Re: Assembler in Delphi! Speichersack?
 
Du vergisst den Stack korrekt aufzuräumen.

Delphi-Quellcode:
asm
  // apt.x div 17
  mov eax, apt.x
  mov ecx, 17
  push edx                          <--- hier EDX auf Stack
  mov edx, 0
  div ecx
  cmp edx, 14
  jns @nowhere                      <---- hier EXIT ohne EDX vom Stack zu holen
  mov x, eax
  // apt.y div 17
  pop edx                           <---- hier EDX vom Stack
  mov eax, apt.y
  mov edx, 0
  div ecx
  cmp edx, 14
  jns @nowhere
  // Result := x + y(eax) * 8
  shl eax, 3
  or eax, x
  cmp eax, 40
  jns @nowhere
  mov @Result, eax
  jmp @1
@nowhere:
  mov @Result, -1 // Result := -1    <----- wenn obiges JNS True ist wird EDX nicht vom Stack geholt
@1:
end;
Zudem verstehe ich nicht warum du
Delphi-Quellcode:
  Result := (apt.x div 17) + (apt.y div 17) * 8
in Assembler als
Delphi-Quellcode:
Result := (apt.x div 17) or (apt.y div 17) * 8
codiert hast.

Zudem JNS = Jump if not sign, Springe wenn EAX < 0 ! ist falsch

Delphi-Quellcode:
function TColorPalette.HitColorText(apt: TPoint): Integer;
{
var x : Integer;
begin
  if PtInRect(ClientRect, apt) then
     if ((apt.x mod 17) > 14) or ((apt.y mod 17) > 14) then
        Result := -1
     else
        Result := (apt.x div 17) + (apt.y div 17) * 8
  else
     Result := -1;
end;}
asm
     // in EAX = Self, EDX = @TPoint

   PUSH EDI
   MOV  ECX,17
   MOV  EAX,[EDX].TPoint.X
   MOV  EDI,[EDX].TPoint.Y
   TEST EAX,EAX
   JS   @@Nowhere       // P.X < 0 ??
   TEST EDI,EDI
   JS   @@Nowhere       // P.Y < 0 ??
   XOR  EDX,EDX
   DIV  ECX
   CMP  EDX,14
   JA   @@Nowhere       // P.X mod 17 > 14 ?? 
   XCHG EAX,EDI         // EDI = P.X div 17
   XOR  EDX,EDX
   DIV  ECX
   CMP  EDX,14
   JA   @@Nowhere
   LEA  EAX,[EDI + EAX * 8] //  Result = P.X div 17 + P.Y div 17 * 8
   JMP  @@Exit
@@Nowhere:
   XOR  EAX,EAX
   DEC  EAX
@@Exit
   POP  EDI
end;
Gruß Hagen

negaH 30. Sep 2003 11:44

Re: Assembler in Delphi! Speichersack?
 
Delphi-Quellcode:
  MOV @Result,-1
Ist schon korrekt gewesen wenn ein lokale Stackframe eingerichtet wurde. Der Assembler macht daraus

Delphi-Quellcode:
  MOV EAX,-1
Gruß Hagen

negaH 30. Sep 2003 11:49

Re: Assembler in Delphi! Speichersack?
 
Übrigens, diese Funktion ist ein ideales Beispiel warum man noch Assembler benutzen sollte.
Denn der Delphi Compiler/Optimierer kann nicht die 4 nötigen Divisionen als 2 Divisionen codieren. Er erkennt deren Abhängigkeiten nicht. Da die Division als solches eine der langsamsten Operationen ist, ist hier ein handgemachter Assembler von Vorteil.

Man kann zwar die Division durch 17 beschleunigen, allerdings nützt das hier nicht viel da wir noch den Modulare Rest durch 17 benötigen. Dafür wiederum gibt es keine schnellere Variante als DIV, vorrausgesetzt wir benötigen den modularen Rest UND den Quotienten zu 17.

Gruß Hagen

neolithos 30. Sep 2003 12:47

Re: Assembler in Delphi! Speichersack?
 
Erstmal danke für die neuen Erkenntnisse!

Delphi-Quellcode:
   JA   @@Nowhere
Delphi-Quellcode:
LEA  EAX,[EDI + EAX * 8] //  Result = P.X div 17 + P.Y div 17 * 8
Doch diese zwi Zeilen sind mir noch unklar? :gruebel:

neolithos 30. Sep 2003 13:07

Re: Assembler in Delphi! Speichersack?
 
So ich habe gerade versucht das gegenstück zu verbessern!

Delphi-Quellcode:
function TColorPalette.GetColorRect(aiCol: Integer): TRect;
var x, y : Integer;
{begin
  if aiCol = -1 then
     Result := Rect(0, 0, 0, 0)
  else
     begin
       x := aiCol mod 8;
       y := aiCol div 8;
       Result := Rect(x * 17, y * 17, x * 17 + 14, y * 17 + 14);
     end;
end; }
asm
  push edi
  test edx, edx
  js @@nullrect // aiCol < 0
  mov edi, 8
  mov eax, edx
  xor edx, edx
  div edi // aiCol div 8
  mov x, edx // = x
  mov y, eax // = y
  mov edi, 17  // Abstand
  // berachne
  mov eax, x
  mul edi
  mov @Result.Left, eax
  mov eax, y
  mul edi
  mov @Result.Top, eax
  mov eax, x
  mul edi
  add eax, 14
  mov @Result.Right, eax
  mov eax, y
  mul edi
  add eax, 14
  mov @Result.Bottom, eax
  jmp @@exit
@@nullrect:
  mov @Result.Left, 0
  mov @Result.Top, 0
  mov @Result.Right, 0
  mov @Result.Bottom, 0
@@exit:
  pop edi
end;
Geht das noch eleganter?
Warum kann man ecx nicht nutzen

neolithos 30. Sep 2003 13:22

Re: Assembler in Delphi! Speichersack?
 
Die division möchte ich nicht dur shr 3 oder and 7 ersetzen da es ja mal 9 oder n spalten werden könnten.

negaH 30. Sep 2003 14:28

Re: Assembler in Delphi! Speichersack?
 
Delphi-Quellcode:
// EAX = Self, EDX = aCol, ECX = @Result.TRect
asm
    TEST EDX,EDX
    JNS  @@1
    XOR  EAX,EAX
    MOV  [ECX].TRect.Left,EAX
    MOV  [ECX].TRect.Right,EAX
    MOV  [ECX].TRect.Top,EAX
    MOV  [ECX].TRect.Bottom,EAX
    RET
@@1:
    MOV  EAX,EDX
    SHR  EDX,3         // aCol div 8
    AND  EAX,7         // aCol mod 8

    LEA  EAX,[EAX * 16 + EAX] // X * 16 + X = X * 17
    LEA  EDX,[EDX * 16 + EDX] // Y * 16 + Y = Y * 17

    MOV  [ECX].TRect.Left,EAX
    MOV  [ECX].TRect.Top,EDX
    ADD  EAX,14
    ADD  EDX,14
    MOV  [ECX].TRect.Right,EAX
    MOV  [ECX].TRect.Borrom,EDX
end;
{
JA = Jump if Above, springe wenn größer, Vorzeichen wird ignoriert
JS = Jump if Sign, springe wenn < 0
JNS = Jump not if Sign, springe nicht wenn < 0, bzw. springe wenn >= 0
LEA = Load Effective Address
}
Gruß Hagen


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:02 Uhr.
Seite 1 von 3  1 23      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz