Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Byte an bestimmter Speicherposition mit Assembler löschen (https://www.delphipraxis.net/114752-byte-bestimmter-speicherposition-mit-assembler-loeschen.html)

Cyf 30. Mai 2008 16:43


Byte an bestimmter Speicherposition mit Assembler löschen
 
Wäre wirklich schön, wenn mir damit jemand helfen könnte, der sich besser damit auskennt.
Ich habe mich mal daran gemacht einige Assemblerfunktionen zu schreiben, um ein wenig dazuzulernen, ob asm bei so etwas sinnvoll ist, sei mal dahin gestellt.
Folgende Funktion soll zusammenhängendes Byte einer Variable oder Instanz löschen (mit 0 füllen).

Delphi-Quellcode:
procedure ByteLoeschen(p: Pointer; Index: Byte); assembler;
asm
  mov EDX, 0FFFFFF00h
  mov CL, BL
  sal Cl, 3  //Linksverschiebung mit Anhängen von Nullen, *2*2*2
  STC //setze Carry-Flag, um kein Bit zu verlieren
  rcl EDX, CL //Rechtsverschuebung mit Anhängen des Carry-Flags, setzt Carry-Flag
  and [EAX], EDX
end;
Das Ganze funktioniert so weit auch ganz gut, meine Frage ist mehr, ob diese Lösung effektiv ist, oder wie "der übliche Weg" für so etwas aussieht (ohne im Pointer gleich den Anfang des zu löschenden Bytes zu übergeben). asm wird ja normalerweise nur benutzt, um Code möglichst effektiv zu gestalten.

3_of_8 30. Mai 2008 16:46

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Also wenn du ein Byte an einer bestimmten Speicherstelle löschen willst, warum benutzt du dann nicht einfach mov dword ptr eax, 0?

Apollonius 30. Mai 2008 16:50

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Wohl eher Byte ptr eax.
@CyF: Funktioniert das? Der zweite Parameter liegt in dl, nicht bl.

Cyf 30. Mai 2008 17:06

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hab die ganze Teit eine Methode gesucht was anderes als 32-Bit Blöcke zu schreiben und hab eine Möglichkeit gesucht es trotzdem zu schaffen... hmm naja, warum auch einfach. :wink:

Habs mal so ersetzt:

Delphi-Quellcode:
procedure ByteLoeschen2(p: Pointer; Index: Byte); assembler;
asm
  mov Byte [EAX + EBX], 0
end;
Dabei scheint es erstaunlicherweiße egal zu sein, ob ich EBX oder EDX nehme, funktioniert beides, was mich etwas verwirrt.
Man sollte aber normalerweiße das 'D'-Register für das 2te Argument nehmen?

Was genau ist mit 'prt' eax gemeint?

3_of_8 30. Mai 2008 17:07

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Natürlich, byte ptr, ich war jetzt irgendwie auf Cardinal...

byte ptr heißt einfach, dass man nicht in EAX schreibt, sondern auf das Byte, das EAX referenziert.

Apollonius 30. Mai 2008 17:08

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Kannst du mal zeigen, wie du deine Funktion aufrufst? Denn EBX zu verwenden ist garantiert falsch.
BYTE PTR EAX ist das selbe wie [EAX], nur das zusätzlich klargestellt wird, dass EAX auf ein Byte und nicht etwa auf ein Word, Dword oder sonstiges zeigt.

Cyf 30. Mai 2008 17:16

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hier mal der Quelltext der ganzen Unit:

Delphi-Quellcode:
unit Main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    BLoeschen: TButton;
    EZahl: TEdit;
    EZahlHex: TEdit;
    EGeloescht: TEdit;
    EGeloeschtHex: TEdit;
    LByte: TLabel;
    EByte: TEdit;
    procedure BLoeschenClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

procedure ByteLoeschen(p: Pointer; Index: Byte);
procedure ByteLoeschen2(p: Pointer; Index: Byte);

var
  Form1: TForm1;

implementation

procedure ByteLoeschen(p: Pointer; Index: Byte); assembler;
asm
  mov EDX, 0FFFFFF00h
  mov CL, BL
  sal Cl, 3  //Linksverschiebung mit Anhängen von Nullen, *2*2*2
  STC //setze Carry-Flag, um kein Bit zu verlieren
  rcl EDX, CL //Rechtsverschuebung mit Anhängen des Carry-Flags, setzt Carry-Flag
  and [EAX], EDX
end;

procedure ByteLoeschen2(p: Pointer; Index: Byte); assembler;
asm
  mov Byte [EAX + EBX], 0
end;

{$R *.dfm}

procedure TForm1.BLoeschenClick(Sender: TObject);
var IntZahl: Integer; ByteNr: Shortint;
begin
  try
    IntZahl:= StrToInt(EZahl.Text);
    ByteNr:= StrToInt(EByte.Text) - 1;
    if((IntZahl < 0) or (ByteNr < 0) or (ByteNr > 3)) then begin
      raise Exception.Create('Ungültiger Wert!');
    end;
    EZahlHex.Text:= IntToHex(IntZahl, 1);
    ByteLoeschen2(@IntZahl, ByteNr);
    EGeloescht.Text:= IntToStr(IntZahl);
    EGeloeschtHex.Text:= IntToHex(IntZahl, 1);
  except
    ShowMessage('Ungültiger Wert!');
  end;
end;

end.
Wenn dadurch klar wird, warum der zweite Parameter auch in EBX liegt, lasst es mich wissen.

Chemiker 30. Mai 2008 17:46

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hallo Cyf,

die Register EAX, ECX und EDX stehen unter Delphi zur freien Verfügung. Willst Du die anderen Register verwenden, so sollte man sie vor der Veränderung auf den Stack packen und vor dem Verlassen in den ursprünglichen Zustand wieder herstellen.

Bis bald Chemiker

Cyf 30. Mai 2008 18:08

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Delphi-Quellcode:
procedure ByteLoeschen(p: Pointer; Index: Byte); assembler;
asm
  mov CL, DL
  mov EDX, 0FFFFFF00h
  sal Cl, 3  //Linksverschiebung mit Anhängen von Nullen, *2*2*2
  STC //setze Carry-Flag, um kein Bit zu verlieren
  rcl EDX, CL //Rechtsverschuebung mit Anhängen des Carry-Flags, setzt Carry-Flag
  and [EAX], EDX
end;

procedure ByteLoeschen2(p: Pointer; Index: Byte); assembler;
asm
  mov Byte [EAX + EDX], 0
end;
Funktionen sind nun so verändert, dass sie EBX nicht mehr verwenden (auch wenn keine Veränderung erfolgte).
Jemand eine Idee, warum EBX den selben Wert wie EDX enthielt (2. Parameter)? (nur aus meiner Neuier herraus :wink: )

Apollonius 30. Mai 2008 18:09

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Schau doch einfach mal in der CPU-Ansicht nach.

Chemiker 30. Mai 2008 18:19

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hallo Cyf,

das wird wahrscheinlich reiner Zufall sein.

Bis bald Chemiker

Cyf 30. Mai 2008 18:49

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Code:
Main.pas.61: ByteLoeschen2(@IntZahl, ByteNr);
00459861 8D45FC          lea eax,[ebp-$04]
00459864 8BD3             mov edx,ebx
00459866 E84DFFFFFF      call ByteLoeschen2
:wall: Das mit der CPU war eine gute Idee, hätte eigentlich gleich den Debugger mal fragen sollen.
Der obige Aufrufcode sollte das ja erklären.

Danke für die Hilfe. :thumb:

brechi 30. Mai 2008 19:10

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
davon abgesehen dass man direkt nen PByte(bla)^ := 0 machen kann (sofern bla dann schon an der richtigen stelle ist)

warum nicht:

Delphi-Quellcode:
procedure ByteLoeschen(p: Pointer; Index: Integer);
asm
  MOV BYTE PTR [EAX+EDX], 0
end;
?

ops gerade erst gesehen dass du das schon hast :)

Laplace 2. Jun 2008 09:21

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Guten Morgen :-D ,

ich möcht' nur noch eine kleine Anmerkung machen:
ich programmier' selber gern in Assembler und in meinen Programmen/Units geb' ich die Übergabekonvention immer explizit an, also (assembler;register;).

Delphi-Quellcode:
Procedure SetZero(P:Pointer;Index:Integer);assembler;register;
ASM
    mov Byte Ptr [eax+edx],0
END;
Bei maximal 3 Übergabeparametern ist 'register' zwar die Standardübergabekonvention (zumindest bei meinem Delphi 4 :oops:), die explizite Angabe bewahrt mich aber ganz sicher vor Überraschungen.


Einen schönen Tag noch
Laplace

Cyf 2. Jun 2008 15:37

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Bei der Gelegenheit wäre vielleicht auch eine Auflistung aller Übergabekonventionen noch mal intressant, konnte aber per Suche keine finden, sind zumindest diese jetzt so korrekt?

register : Die ersten drei Argumente der Reihenfolge nach in EAX, EDX und ECX, ggf. die Restlichen auf dem Stack
Zitat:

Der erste Parameter von links, der auf den Stack geschoben wird, wird im Gegensatz zu CDecl, StdCall und Safecall als erstes auf den Stack geschoben und liegt damit, wie übrigens auch bei Pascal, zuunterst.
Standard-Aufrufkonvention.

stdcall: Alle Argumente auf dem Stack, auch hier wieder je weiter hinten, desto weiter "unten"

Es gibt noch CDecl, aber wie sie da angeordnet sind bin ich nicht sicher.

Wäre eventuell sinnvoll, das in einem extra Thema mal zu sammeln, weil das sicher immer mal wieder intresannt sein kann. (auch z.B. für dll s)

[EDIT] Fehler beseitigt, nicht das es hier wer falsch liest. :stupid:

FAlter 2. Jun 2008 15:49

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hi,

Zitat:

Zitat von Laplace
ich programmier' selber gern in Assembler und in meinen Programmen/Units geb' ich die Übergabekonvention immer explizit an, also (assembler;register;).

[...] die explizite Angabe bewahrt mich aber ganz sicher vor Überraschungen.

Dann solltest du das "assembler" aber weglassen, denn veralgtete Schlüsselworte können manchmal für Überraschungen sorgen. Wie die Überraschung, dass "inline" eine neue Bedeutung bekommen hat...

Aus der D7-Hilfe:

Zitat:

The reserved word inline and the directive assembler are maintained for backward compatibility only. They have no effect on the compiler.
Aus der Turbo-Delphi-Hilfe (D2006):

Zitat:

Beim Delphi-Compiler ermöglicht zur Verbesserung der Leistung, Funktionen und Prozeduren mit der Direktive inline zu versehen. Wenn eine Funktion oder Prozedur bestimmten Kriterien entspricht, fügt der Compiler Code direkt ein anstatt einen Aufruf zu generieren. Das Ergebnis dieser Leistungsoptimierung ist schnellerer Code, der jedoch mehr Speicherplatz in Anspruch nimmt. Der Compiler produziert dabei eine größere Binärdatei. Die Direktive inline wird in Funktions- und Prozedurdeklarationen und -definitionen, genau wie andere Direktiven, verwendet.
Wer weiß, wie es bald mal mit "assembler" aussehen wird?

Mfg
FAlter

Apollonius 2. Jun 2008 16:56

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Die fünf in Delphi verfügbaren Aufrufkonventionen sind in der Delphi-Hilfe und bei Luckie aufgelistet.
CyFs Beschreibung von Register ist nicht ganz korrekt: Der erste Parameter von links, der auf den Stack geschoben wird, wird im Gegensatz zu CDecl, StdCall und Safecall als erstes auf den Stack geschoben und liegt damit, wie übrigens auch bei Pascal, zuunterst.

@Laplace: Die Standard-Aufrufkonvention ist unabhängig von der Parameteranzahl und der Delphi-Version immer Register.

Laplace 2. Jun 2008 20:11

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hallo Appolonius :hi:,

soweit ich weiß, sind (zumindest in D4) nur EAX, EDX und ECX in Assembler frei verfügbar. Wenn du mehr als 3 Parameter übergeben willst, reichen die Register also (alleine) nicht aus.


Hallo FAlter :) ,

die angegebene Syntax (assembler;register) stammt aus dem Handbuch für Delphi 4. Mag bei anderen Compilerversionen unterschiedlich sein. Aber danke für deinen Hinweis :P .


Schönen Abend noch
Laplace

Apollonius 2. Jun 2008 20:14

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hallo Laplace,
das ist natürlich richtig. Doch zur Aufrufkonvention Register gehört eben auch, dass überzählige Parameter in der Reihenfolge der Deklaration auf den Stack gepusht werden. Nur weil es zu viele (oder zu große) Parameter sind, wird also nicht plötzlich die Aufrufkonvention StdCall verwendet.
Grüße
Apollonius

Laplace 2. Jun 2008 20:22

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hallo Appolonius :-D ,

weiß schon.
Bei mir ist's so, dass immer wenn ich eine interne Funktion bzw. Prozedur mit max. 3 Parametern aufrufen/schreiben kann, dann juckt's mich, das in assembler zu schreiben - hauptsächlich bei Stringoperationen. Maximal 3 Parameter halte ich für (interne) Assemblerroutinen als fast optimal.
Ansonsten ist mir das eher zu 'unübersichtlich' und weiche (nur) notfalls auf die Deklaration 'pascal' aus.


Schönen Abend noch
Laplace

Apollonius 2. Jun 2008 20:48

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Wieso verwendest du denn überhaupt Pascal und nicht immer Register?

Laplace 3. Jun 2008 06:10

Re: Byte an bestimmter Speicherposition mit Assembler lösche
 
Hallo Apollonius :hi:,

bei der Aufrufkonvention 'pascal' sind für mich die Verhältnisse klarer.

Bei 'register' werden die ersten 3 Parameter über eax, edx, ecx übergeben, der Rest über den Stack (siehe Cyf's post oben). Da ich manchmal die Übergabeparameter (Anzahl und/oder Reihenfolge) im Laufe der Programmierung einer Prozedur/Funktion noch ändere :oops:, müßte ich in diesem Fall darauf achten, an welcher Position ein bestimmter Parameter übergeben wird.
Dazu bin ich zu bequem (= zu faul :mrgreen:).

Bei der Konvention 'pascal' ist der Zugriff einheitlich über den Stack :thumb:.


Schönen Tag noch
Laplace

P.S. Übrigens:
Zitat:

Die Standard-Aufrufkonvention ist unabhängig von der Parameteranzahl und der Delphi-Version immer Register.
Stimmt, hab' mich da falsch ausgedrückt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:46 Uhr.

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