Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Verdrehte Bits (Wilde Pointereien) (https://www.delphipraxis.net/97815-verdrehte-bits-wilde-pointereien.html)

Phoenix 16. Aug 2007 18:59


Verdrehte Bits (Wilde Pointereien)
 
Ich lese (soll lesen) Daten aus einer SPS aus und packe diese in eine Datenbank.

Das klappt einwandfrei. Folgendes steht Testweise in der SPS und dann auch im Blob:
Code:
00 01 00 14 00 1E 00 28 00 32 00 3C 00 00 00 00 00 00 00 00
Nun lese ich den Blob und packe den aus Performancegründen in einen selber allokierten Speicherbereich mit der Länge des Datenbausteins.

Um gezielt auf einzelne Bytes zugreifen zu können, speichere ich den Pointer aus GetMem als PByteArray.
Greife ich nun so auf die Daten zu:
Delphi-Quellcode:
i := 0;

while i < dm.ModuleLength do
begin
  Memo1.Lines.Add('Byte ' + IntToStr(i) + ' : ' + IntToStr(dm.Bytes[i]));
  Inc(i);
end;
Wobei dm mein Datenbaustein (DataModule) ist und dm.Bytes folgendermassen deklariert ist:
Delphi-Quellcode:
FData: PByteArray;
property Bytes[AIndex: Integer]: Byte read GetBytes;
//...
function PLCDataModule.GetBytes(AIndex: Integer): Byte;
begin
  Result := FData^[AIndex];
end;
Bekomme ich folgende Ausgabe:
Code:
Byte 0 : 0
Byte 1 : 1
Byte 2 : 0
Byte 3 : 20
Byte 4 : 0
Byte 5 : 30
Byte 6 : 0
Byte 7 : 40
Byte 8 : 0
Byte 9 : 50
Byte 10 : 0
Byte 11 : 60
Byte 12 : 0
...
Was exakt das ist, was ich erwarte.

Nun zum Problem:

Manche Datenbereiche in der SPS sind größer als ein Byte. In der Regel habe ich es mit 2- oder gar 4 Byte grossen Einträgen zu tun, die ich gegen Bitmasken mit verschiedenen Operatoren (Gleichheit, invertiert verandetet) prüfen muss, um bestimmte Status abzufragen. Diese Bitmasken kann ich also wahlweise als Integer oder als Cardinal speichern. Zur Zeit sind es Integers.

Da die Datenbereiche aber Unregelmässig sind (z.B. 1 Byte, 1 Byte, 6 Byte) kann ich den Pointer nicht auf ein Integer-Array umcasten und den Index (Startbyte) durch 4 Teilen. Das heisst ich muss von einem Pointer auf ein Byte 4 Bytes lesen.

Das mache ich so:
Delphi-Quellcode:
Result := PInteger(Integer(FData) + AIndex)^;
Rufe ich das in der gleichen Schleife wie oben alle 4 Bytes, beginnend beim Nullten, auf, bekomme ich folgende Ausgabe:
Code:
Wert 0 : 335544576
Byte 0 : 0
Byte 1 : 1
Byte 2 : 0
Byte 3 : 20
Wert 1 : 671096320
Byte 4 : 0
Byte 5 : 30
Byte 6 : 0
Byte 7 : 40
Wert 2 : 1006645760
Byte 8 : 0
Byte 9 : 50
Byte 10 : 0
Byte 11 : 60
Das ist nicht, was ich erwarte. Denn wenn ich diese Werte in binäre Daten umwandele, dann erhalte ich folgendes:

Code:
Byte 0 - 11 laut der ersten Einzelbyte-Ausgabe:

0  = 00000000 
1  = 00000001
0  = 00000000
20 = 00010100

0  = 00000000
30 = 00011110
0  = 00000000
40 = 00101000

0  = 00000000
50 = 00110010
0  = 00000000
60 = 00111100

Laut dem Windows-Calculator haben diese 3x4 Bytes folgende Werte:

00000000 00000001 00000000 00010100 b =  65556 d
00000000 00011110 00000000 00101000 b = 1966120 d
00000000 00110010 00000000 00111100 b = 3276860 d

Die Werte aus der Ausgabe geben jedoch:

00010100 00000000 00000001 00000000 b = 335544576 d
00101000 00000000 00011110 00000000 b = 671096320 d
00111100 00000000 00110010 00000000 b = 1006645760 d
Warum verdreht die andere Zahlendarstellung auf einmal meine Bytes?
Ich meine, sie stehen ja offenbar auch definitiv andersrum im Speicher.

Nur wenn ich einen Status definiere, der z.B. die ersten 4 Bits prüfen soll, und dann
Code:
11110000 00000000 00000000 00000000 vs.
00000000 00000000 00000000 11110000
verglichen wird, dann gibt das freilich ein False, obwohl ich ein True bräuchte.

Was kann ich da machen?

Olli 16. Aug 2007 19:13

Re: Verdrehte Bits (Wilde Pointereien)
 
Das schnellste ist ein "BSWAP" (inline-Assembler).

Das Problem ist das Gleiche in Windows. Sobald nämlich mehr als ein Byte dabei ist, kommst du in Probleme mit der Byte-Reihenfolge, zumindest ist das theoretisch der Fall.

Suche hier:
http://jedi-apilib.cvs.sourceforge.n...11&view=markup
nach "RtlUlongByteSwap" und kopiere den Code. Ist von mir und du darfst es auch ohne die MPL/LGPL verwenden. Wegen einem zweibytigen Opcode muß ich keine Erwähnung irgendwo haben :mrgreen:

Auch:
MSDN-Library durchsuchenhtonl
MSDN-Library durchsuchenntohl

Ach was, hier ist sie:

Delphi-Quellcode:
function RtlUlongByteSwap(Source: ULONG): ULONG;
asm
  // This is not written as mnemonics to be compatible with D4!
  db   0Fh, 0C8h      // "bswap EAX" can only be executed on 486+!!!
(*
  // Does the same but perhaps slower ...
                        // Source = $11223344
  rol  AX, 08h       // Source = $11224433
  rol  EAX, 0Fh       // Source = $44331122
  rol  AX, 08h       // Source = $44332211
*)
end;

Phoenix 16. Aug 2007 19:30

Re: Verdrehte Bits (Wilde Pointereien)
 
Hrm. Ich hab mir grad meine SPS-Layout-Konfiguration zerlegt, weil ich blöderweise von der Datenbank nur Integer lese und der mir natürlich dank Vorzeichen irgendwann umkippt. Jetzt hab ich Kopfschmerzen und keinen Nerv mehr dafür.

Als was ist denn ULONG definiert?

Und würde es ggf. reichen, hier bei meinen Operationen die Bereichsprüfung zu deaktivieren, damit ich auch Werte > MAX_INT in einen int Reinschreiben kann, solange meine Bitfolge passt?

Neutral General 16. Aug 2007 19:34

Re: Verdrehte Bits (Wilde Pointereien)
 
Hi,

Zitat:

Als was ist denn ULONG definiert?
Delphi-Quellcode:
uses Windows;

type
 ULONG = Cardinal;
Gruß
Neutral General

Olli 16. Aug 2007 19:46

Re: Verdrehte Bits (Wilde Pointereien)
 
Vorzeichenloser 32bittiger Ganzzahltyp.

Übrigens:

DWORD und PDWORD sind auch in Windows.pas deklariert und ULONG entspricht DWORD, womit nix mehr "umkippt" :mrgreen: :zwinker:

Phoenix 16. Aug 2007 21:04

Re: Verdrehte Bits (Wilde Pointereien)
 
Ich glaub ich pack die 'Bitmaske' dann am besten als Float in die Datenbank und Runde die dann beim wieder auslesen auf einen ganzzahligen DWORD.

Dann hab ich auch kein Problem mit dem Eingabeformular, das ist ein bisschen Tricky, weil ich da die Bitmaske als String von 0 und 1, als einzelne Checkboxen für jedes Bit und eben als Zahl eingeben kann.

Und sollte irgend ein SPS'ler irgendwann mal meinen, er müsste 5 oder gar 6 Byte für ein Gerät verwenden, dann hab ich damit auch keine Probleme ;-)

Chemiker 16. Aug 2007 21:51

Re: Verdrehte Bits (Wilde Pointereien)
 
Hallo Phoenix,

rein interessehalber, liest Du die Daten aus der SPS, oder werden die Daten von der SPS gesendet?

Bis bald Chemiker

Phoenix 16. Aug 2007 22:07

Re: Verdrehte Bits (Wilde Pointereien)
 
Ich fetche sie selber aus der SPS. Die sendet nix von alleine.

Chemiker 16. Aug 2007 22:16

Re: Verdrehte Bits (Wilde Pointereien)
 
Hallo Phoenix,

Aber normalerweise kann die SPS doch Dir die Daten zur Verfügung stellen. Durch einen Timer (z.B.: jede Sekunde) in der SPS können die Messdaten doch übermittelt werden, oder liest Du das Programm der SPS?

Bis bald Chemiker

Phoenix 16. Aug 2007 22:42

Re: Verdrehte Bits (Wilde Pointereien)
 
Nein, ich lese die Datenbausteine aus. Aber es geht hier nicht nur um Messdaten, sondern um eine komplette gesteuerte Anlage, von der ich alle - also wirklich sämtliche - Status brauche.

Wenn die SPS mir die Daten aktiv sendet, geht das von der Zykluszeit ab.
Wenn ich die Daten hingegen selber fetche, dann erzeugt das keine Last auf der SPS.

Und wenn da tausende kleiner Pakete durch eine Anlage flitzen, dann braucht die SPS jede Millisekunde die sie bekommen kann, um die rechtzeitig an die richtige Stelle zu schubsen ;-) Wenn dann so ein Kerle daher kommt, und sich dann auch noch Daten - nur um sie hybsch an einem Monitor anzuzeigen - senden lassen will, dann lachen die SPS-Programmierer mal herzhaft und lassen den Kerle - also mich - links liegen ;-)

Edit Nachtrag: Verdammich. Ich werde mich NIE an Status als Mehrzahl von Status gewöhnen. *brr*

3_of_8 16. Aug 2007 23:07

Re: Verdrehte Bits (Wilde Pointereien)
 
Das gute, alte Big Endian vs. Little Endian-Problem, wenn ich richtig sehe. Es würde z.B. so gehen:

Delphi-Quellcode:
function LittleBigIsEqual(const a, b: Integer): Boolean;
type TIntByteArray=array[0..3] of Byte;
begin
  Result:=(TIntByteArray(a)[0]=TIntByteArray(b)[3]) and
    (TIntByteArray(a)[1]=TIntByteArray(b)[2]) and
    (TIntByteArray(a)[2]=TIntByteArray(b)[1]) and
    (TIntByteArray(a)[3]=TIntByteArray(b)[0]);
end;
Einfacher wäre es vielleicht, wenn du das ganze byteweise holst.

Chemiker 16. Aug 2007 23:44

Re: Verdrehte Bits (Wilde Pointereien)
 
Hallo Phoenix,

die Anlage wird doch mit dem Programm der SPS gesteuert, oder wird mit Deinem Programm während die Anlage läuft Parameter verändert im SPS – Programm? Das würde ich aber für sehr gefährlich halten, weil es eigentlich den Sinn der SPS untergräbt, sonst würde man doch direkt einen PC für die Steuerung der Anlage benutzen.

Und der Status der Anlage sind doch auch Messdaten. Bei Paketen vermute ich mal werden z.B. Zähler, Lichtschranken, Barcodeleser, Geschwindigkeit des Bandes usw. vorhanden sein.

Also bei uns währe es nicht möglich direkt auf die SPS zuzugreifen und Daten auszulesen, weil es da zu leicht zu Fehlern kommen könnte. Es ist auch kein Problem für die SPS die Daten zu senden, bei uns kann die SPS mehr Daten senden als der Rechner überhaut verkraften kann. Deswegen sind wir dazu übergegangen das die SPS nur alle 5 sek. die Daten zum Rechner senden.

Bis bald Chemiker

oldmax 17. Aug 2007 05:46

Re: Verdrehte Bits (Wilde Pointereien)
 
Hi
Nun, ich weiß nicht, um was für eine SPS es sich handelt (Siemens, BBC, Mitsubishi... ) aber eine SPS wird nicht durch den Zugriff und Senden von Datenpaketen an irgendeine Visualisierung ausgebremst und wenn SPS-Programmierer das behaupten, haben sie entweder keine Ahnung oder keine Lust. (letzteres vermutlich, weil man nicht immer gleich einsieht, das so ein Tastenklimperer SPS-Daten haben will...)
Nun ist es auch nicht möglich, das zu lesende Daten im Programm Stolpersteinchen hinterläßt, dazu gehören auch notwendigerweise Schreibzugriffe. Wenn dabei Prozeßrelevante Daten von Rezeptdaten getrennt sind, ist ein schreibender Zugriff auf SPS Datenbausteine kein Problem. Natürlich steht da eine Maschine hinter, die das tut, was im Speicher an Programm hinterlegt ist und da braucht's schon etwas mehr Erfahrung und mit "ich probier mal so" sollte man auch vorsichtig sein.
Ok, Nun zum Problem. Es ist schon ein Unterschied, ob ich Binärinformation oder Zahlenwerte aus einem DB lese. Da diese richtig schön gemischt sein können, ist es notwendig, zu wissen, was steht wo und das sollte in der Doku der DB's hinterlegt sein. ( Ansonsten hat der SPS-Programmierer bös geschlampt und der Nachwelt ein überdimensionales Rätsel hinterlassen...)
Du kannst die Daten entsprechend Byte oder Wortweise aus dem DB holen, mußt dann aber dafür sorgen, das Zahlen und Binärinfos getrennt ausgewertet werden. Floatwerte über Binärmasken zu schicken halte ich für möglich, aber nicht für Sinnvoll, da hat ein PC doch andere Möglichkeiten Daten unverfälscht aufzuarbeiten. Wie gesagt, du mußt nachsehen, was ist Binär, was ist Integer und was Float. Und nicht zu vergessen, manchmal steht auch Text im DB.
Gruß oldmax
( eine von mir betreute Anlage ist 200m lang und das Schalthaus dazu in 2 Etagen, ca. sieben SPS und jede Menge dezentrale Peripherie und Datenkommunikation......)

Phoenix 17. Aug 2007 07:28

Re: Verdrehte Bits (Wilde Pointereien)
 
Es geht doch gar nicht um das fetchen der Daten aus der (Siemens-) SPS ;-)

Da wir in einer Anlage ggf. ZIG Visualisierungsrechner haben, und es vermieden werden soll, dass alle diese Rechner direkt von der SPS beschickt werden oder selber aus der SPS lesen müssen - das hat zum Teil damit zu tun, dass es zwischen Anlage und Verwaltung meistens eine Firewall gibt, die diese zwei Netze bis auf die Datenbank trennt - gibt es eben einen Service, der die kompletten Datenbausteine in einem konfigurierbaren Intervall aus der SPS liest und in die Datenbank schreibt. Und dort stehen sie ja auch richtig drin. Das läuft, das war vorgegeben, da hab ich schon fertigen Code zum Fetchen bekommen, und ich werde einen Teufel tun mich hier deswegen mit meinem Auftraggeber zu streiten ;-)

Die alte Visualisierung die ich gerade erneuere neu schreibe ist nach dem Fetchen hergegangen, und hat jedes einzelne Bit aus dem DB als eigenen Datensatz(!) in die Datenbank gepumpt. Das Problem war dann der Traffic, der ein einzelner Client auf dem Netz erzeugt hat, wenn dort einer die Visumaske aufgemacht hat. Das war dann noch so unglücklich gemacht, dass der echt für jedes Bit ein einzelnes Statement zum holen von der Datenbank gefeuert hat.

Deswegen war meine Idee, das aufdröseln der Daten in die einzelnen Bits eben auf den Client auszulagern, und die Datenbausteine komplett als Blob in die DB zu legen. Dort kann dann jeder der will darauf auswerten und gucken, welcher Antrieb läuft, welcher auf Handsteuerung läuft und wo ggf. welche Störung anliegt.

Ob nun Bits oder Zahlen in dem DB liegen ist mir recht wurscht. Ob die 10 in dem Byte da drin nun bedeutet, dass es die Zahl 10 ist oder dass da das zweite und vierte Bit (von rechts gesehen) gesetzt sind, das kann ich mit meiner Bitmasken-Prüfung einheitlich abfackeln. Auch Texte sind kein Problem.

Meine Frage bezog sich tatsächlich nur auf die Verdrehung der Bytes, sobald ich sie in einen Cardinal stecke. Und nun werde ich das mal mit einem DWORD probieren und gucken ob ich da dann noch drehen muss oder nicht ;-)

Phoenix 17. Aug 2007 07:35

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von 3_of_8
Einfacher wäre es vielleicht, wenn du das ganze byteweise holst.

Einfacher ja, aber auf jeden Fall lansgamer. Und ich will vermeiden, dass es flackert wenn sich die Visu neu zeichnet und dazu die Daten aus dem Stream liest.

divBy0 17. Aug 2007 07:39

Re: Verdrehte Bits (Wilde Pointereien)
 
Das verdrehen der Bytes ist bei der S7 aber normal.

Wie ließt du die Daten denn aus der SPS? Mit LibNoDave?

Phoenix 17. Aug 2007 07:50

Re: Verdrehte Bits (Wilde Pointereien)
 
Nochmal langsam zum Mitschreiben *seufz*:
Die Daten werden in der richtigen Reihenfolge von der SPS gelesen.
Die Daten werden in der richtigen Reihenfolge in die Datenbank geschrieben.
Die Daten werden in der richtigen Reihenfolge aus der Datenbank gelesen.
Die Daten werden in der richtigen Reihenfolge in ein Array of Byte geschrieben.
Die Daten werden in der richtigen Reihenfolge aus dem Array of Byte gelesen.

Wenn ich dann jedoch
Delphi-Quellcode:
PCardinal( Integer(PByteArrayPointer) + AStartByte )^
mache, DANN und nicht vorher, werden meine Bytes verwürfelt.

Edit: Aber um Frage dennoch zu beantworten: Für die SPS-Kommunikation werden die LUCA-Komponenten von Langner genommen.

Phoenix 17. Aug 2007 09:02

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von Olli
Suche hier:
http://jedi-apilib.cvs.sourceforge.n...11&view=markup
nach "RtlUlongByteSwap" und kopiere den Code. Ist von mir und du darfst es auch ohne die MPL/LGPL verwenden. Wegen einem zweibytigen Opcode muß ich keine Erwähnung irgendwo haben :mrgreen:

Ach was, hier ist sie:

Delphi-Quellcode:
function RtlUlongByteSwap(Source: ULONG): ULONG;
asm
  // This is not written as mnemonics to be compatible with D4!
  db   0Fh, 0C8h      // "bswap EAX" can only be executed on 486+!!!
(*
  // Does the same but perhaps slower ...
                        // Source = $11223344
  rol  AX, 08h       // Source = $11224433
  rol  EAX, 0Fh       // Source = $44331122
  rol  AX, 08h       // Source = $44332211
*)
end;

Hrm.

Ich habe die jetzt so eingebaut:
Delphi-Quellcode:
function TPLCDataModule.SwapBytes(Source: DWORD): DWORD;
asm
  // This is not written as mnemonics to be compatible with D4!
  db 0Fh, 0C8h      // "bswap EAX" can only be executed on 486+!!!
end;
Gibt nur ein Problem damit:
Seltsamerweise liefert die IMMER 888723972 zurück.

Das hier liefert übrigens den richtigen Wert:
Delphi-Quellcode:
Result := Cardinal( (FData^[AIndex] shl 24) + (FData^[AIndex + 1] shl 16) + (FData^[AIndex + 2] shl 8) + FData^[AIndex + 3] );
Aber ich befürchte, das ist um ca. den Faktor vier langsamer, als die Teile am Block rauszulesen.

Oder kann mich da wer beruhigen?

Hawkeye219 17. Aug 2007 09:09

Re: Verdrehte Bits (Wilde Pointereien)
 
Hi Sebastian,

wenn du SwapBytes als Methode definierst, steht im Register EAX der Zeiger auf die aktuelle Instanz, das eigentliche Argument Source wird im Register EDX übergeben. Das Tauschen ist aber unabhängig von der Klasse, deshalb würde ich es als einfache Funktion definieren:

Delphi-Quellcode:
function SwapBytes (Source: DWORD): DWORD;
asm
  // This is not written as mnemonics to be compatible with D4!
  db 0Fh, 0C8h      // "bswap EAX" can only be executed on 486+!!!
end;
Gruß Hawkeye

Phoenix 17. Aug 2007 09:19

Re: Verdrehte Bits (Wilde Pointereien)
 
:wall:

Ich glaub ich brauch heut noch nen Extra-Kaffee zum wachwerden. Klaro.. fühl mich heut früh wie ein Anfänger .oO

Quake 2. Sep 2007 14:48

Re: Verdrehte Bits (Wilde Pointereien)
 
Nur mal als Hinweis, weil ich mich auch gerade damit rumschlage.

(Edit : Damit das hier nicht falsch stehen bleibt änder ich das mal.)
Die CPUs, die auf der Intel Architektur (8086) basieren, legen das niederwertigste Byte zuerst im Speicher ab.
Im Gegensatz dazu legen die CPUs, die auf der Motoroler Architektur (6800) basieren, das höstwertigste Byte zuerst im Speicher ab.

Deswegen ist Delphi doch manchmal ein ganz schöner Krampf. Bei meiner Anwendung, die ich im Moment schreibe, kommt es nähmlich auch auf die Geschwindigkeit an.

Noch eine Sache zu dem "ULONG" das kommt von unsigned long, die C++ler werden damit eher was anfangen können.

Mit dem Inlineassembler habe ich noch nicht so richtig verstanden,da ich damit noch nicht gearbeitet habe. Vieleicht kann mir da ja noch jemand helfen. Ich habe jetzt mitten in einer Procedure eine Variable "w: longword;", wie bekomme ich diese Variable jetzt in dass EAX Register und das Ergebniss wieder Zurück in meine Variable?

Christian Seehase 2. Sep 2007 15:13

Re: Verdrehte Bits (Wilde Pointereien)
 
Moin Quake,

Zitat:

Zitat von Quake
Die CPUs, die auf der Intel Architektur (8086) basieren, legen das höstwertigste Byte zuerst im Speicher ab.
Im Gegensatz dazu legen die CPUs, die auf der Motoroler Architektur (6800) basieren, das niederwertigste Byte zuerst im Speicher ab.

Umgekehrt ;-)

Intel arbeite mit Little-Endian, Motorola mit Big-Endian.

Quake 2. Sep 2007 15:24

Re: Verdrehte Bits (Wilde Pointereien)
 
Ups :oops: Du hast natürlich Recht. Habe ich oben mal schnell geändert :stupid: .

OK, habe mir das schon selbst beantwortet: (Beispiel ist eine vereinfachte Version)

Delphi-Quellcode:
procedure xyz(Zahl: longword);
var
  l: longword;
begin
  l := Zahl;
  asm
    mov eax, l;
    bswap eax;
    mov l, eax;
  end;
  Zahl := l;
end;

Olli 2. Sep 2007 16:00

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von Quake
Mit dem Inlineassembler habe ich noch nicht so richtig verstanden,da ich damit noch nicht gearbeitet habe. Vieleicht kann mir da ja noch jemand helfen. Ich habe jetzt mitten in einer Procedure eine Variable "w: longword;", wie bekomme ich diese Variable jetzt in dass EAX Register und das Ergebniss wieder Zurück in meine Variable?

Indem du den entsprechenden Namen der Variablen oder deren Stackposition ansprichst?!

Wo hakt es denn genau?

Das Ergebniss wird übrigens bei einem 32bit-Wert oder Pointer oder weniger als 32bit (Boolean) in EAX zurückgegeben.

Quake 2. Sep 2007 16:38

Re: Verdrehte Bits (Wilde Pointereien)
 
Danke für dein Angebot der Hilfe, aber ich habe es schon hin bekommen. (siehe oben)

Ich habe aber noch eine kleine Abänderung gemacht, jetzt mit einem Pointer. (wieder die Vereinfachte Version)

Delphi-Quellcode:
procedure xyz(Zahl: longword);
var
  p: ^longword;
begin
  .
  .
  .
  p := @Zahl;
  asm
    mov edx, p;
    mov eax, [edx];
    bswap eax;
    mov [edx], eax;
  end;
  .
  .
  .
end;
Eine Frage habe ich doch noch. Dies könnte ich doch auch in ein Macro packen, oder? Wie erstelle ich nur ein Macro?

Olli 2. Sep 2007 16:44

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von Quake
Danke für dein Angebot der Hilfe, aber ich habe es schon hin bekommen. (siehe oben)

Ich habe aber noch eine kleine Abänderung gemacht, jetzt mit einem Pointer. (wieder die Vereinfachte Version)

Delphi-Quellcode:
procedure xyz(Zahl: longword);
var
  p: ^longword;
begin
  .
  .
  .
  p^ := @Zahl;
  asm
    mov edx, p;
    mov eax, [edx];
    bswap eax;
    mov [edx], eax;
  end;
  .
  .
  .
end;

Hmpf ... nicht gut. Ich sehe, daß du die Zahl nicht zurückgeben willst, also wird sie vermutlich nach dem Assemblerblock verarbeitet. Nur als kleiner Tip, meine Funktion von oben sollte deutlich effektiver sein. Warum? Weil du überflüssige Dinge machst und mal davon abgesehen auch noch riskant. Was passiert mit EDX und EAX vor und nach dem Assemblerblock? Weißt du nicht? Richtig! Also müssen sie gesichert werden!

Delphi-Quellcode:
// Siehe dein Code
  p^ := @Zahl;
  asm
    push edx
    push eax
    mov edx, p;
    mov eax, [edx];
    bswap eax;
    mov [edx], eax;
    pop eax
    pop edx
  end;

Quake 2. Sep 2007 16:54

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Was passiert mit EDX und EAX vor und nach dem Assemblerblock?
Da hast du wohl Recht, aber ich habe irgendo eben gelesen, dass das Delphi auch egal ist. Andere Register wie z.B. ESP, EDI usw. müssen dagegen auf jeden Fall gesichert werden. Ausserdem funktioniert mein Code so wie ich ihn da stehen habe.
Edit: Hab nochmal nachgeschaut, in der Delphi-Hilfe steht das so drin.

Zitat:

Weil du überflüssige Dinge machst
Wo mache ich was überflüssig?

Zitat:

Hmpf ... nicht gut. Ich sehe, daß du die Zahl nicht zurückgeben willst, also wird sie vermutlich nach dem Assemblerblock verarbeitet.
Ja, der Code oben sollte nur ein Ausschnitt aus meinem Code sein.

Olli 2. Sep 2007 17:23

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von Quake
Da hast du wohl Recht, aber ich habe irgendo eben gelesen, dass das Delphi auch egal ist. Andere Register wie z.B. ESP, EDI usw. müssen dagegen auf jeden Fall gesichert werden. Ausserdem funktioniert mein Code so wie ich ihn da stehen habe.
Edit: Hab nochmal nachgeschaut, in der Delphi-Hilfe steht das so drin.

Das ist schön. Zitiere doch bitte mal den ganzen Absatz hier, weil ich mir ziemlich sicher bin, daß du bei einer Funktion, welche nicht komplett in Inline-ASM geschrieben ist, auch die Register sichern mußt.

Überflüssig wäre das ganze hinundherkopieren, weil du das bei dem Aufruf einer anderen Funktion nicht brauchst.

Quake 2. Sep 2007 20:15

Re: Verdrehte Bits (Wilde Pointereien)
 
Onlinehilfe :
Zitat:

Registerverwendung

Im Allgemeinen sind die Regeln für die Verwendung von Registern in einer asm-Anweisung identisch mit denjenigen für eine external-Prozedur oder -Funktion. In einer asm-Anweisung muss der Inhalt der Register EDI, ESI, ESP, EBP und EBX erhalten bleiben, während die Register EAX, ECX und EDX beliebig geändert werden können. Beim Eintritt in eine asm-Anweisung zeigt EBP auf den aktuellen Stackframe, ESP auf den Beginn des Stacks. Zu Beginn der Ausführung einer asm-Anweisung ist der Registerinhalt unbekannt. Eine Ausnahme bilden die Register ESP und EBP.


Zitat:

Überflüssig wäre das ganze hinundherkopieren, weil du das bei dem Aufruf einer anderen Funktion nicht brauchst.
Dann kannst du mir auch bestimmt erklären, wieviel Zeit Verschwendet wird, bei einmal eine Variable hin und her kopieren im Gegensatz zu einem Funktionsaufruf. Was macht Delphi wohl automatisch wenn eine Funktion aufgerufen wird? Ich gehe mal davon aus, zum einen Unmengen von Daten hin und her kopieren, und zum anderen eine Bereichsüberprüfung.

Apollonius 2. Sep 2007 20:19

Re: Verdrehte Bits (Wilde Pointereien)
 
Was soll denn das Rumgezeigere? Was spricht gegen
Delphi-Quellcode:
asm
mov eax, zahl
bswap eax
mov zahl, eax
end;

Quake 2. Sep 2007 20:35

Re: Verdrehte Bits (Wilde Pointereien)
 
Meine Codes sind nur Beispiele. Ich habe nicht geschrieben, das dies so 1:1 übernommen werden muss. Je nach Anwendunsfall, bzw. je nach dem Code der vor und nach dem asm-Block steht muss man sich selbst raus suchen was man selbst benötigt.

Olli 2. Sep 2007 20:36

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von Quake
Onlinehilfe :
Zitat:

Registerverwendung

Im Allgemeinen sind die Regeln für die Verwendung von Registern in einer asm-Anweisung identisch mit denjenigen für eine external-Prozedur oder -Funktion. In einer asm-Anweisung muss der Inhalt der Register EDI, ESI, ESP, EBP und EBX erhalten bleiben, während die Register EAX, ECX und EDX beliebig geändert werden können. Beim Eintritt in eine asm-Anweisung zeigt EBP auf den aktuellen Stackframe, ESP auf den Beginn des Stacks. Zu Beginn der Ausführung einer asm-Anweisung ist der Registerinhalt unbekannt. Eine Ausnahme bilden die Register ESP und EBP.

Dann will ich nichts gesagt haben. In dem Fall sollte es gehen. Ich habe nur eben kein Delphi installiert.

Zitat:

Zitat von Quake
Zitat:

Überflüssig wäre das ganze hinundherkopieren, weil du das bei dem Aufruf einer anderen Funktion nicht brauchst.
Dann kannst du mir auch bestimmt erklären, wieviel Zeit Verschwendet wird, bei einmal eine Variable hin und her kopieren im Gegensatz zu einem Funktionsaufruf.

Nein, kann ich nicht, weil das vom Prozessor und da vom Modell usw. abhängt. Das ändert sich ständig, weshalb sogenannte "Optimierungen" mit Assembler meist gröbster Unsinn sind. Im Falle von BSWAP haben wir eine Ausnahme, weil dort eine Instruktion die Arbeit von mehreren Zeilen HLL-Code macht.

Zitat:

Zitat von Quake
Was macht Delphi wohl automatisch wenn eine Funktion aufgerufen wird? Ich gehe mal davon aus, zum einen Unmengen von Daten hin und her kopieren, und zum anderen eine Bereichsüberprüfung.

Und genau da irrst du bei einer Funktion, die kein begin/end, sondern asm/end hat. Dort passiert nämlich nichts dergleichen.

Olli 2. Sep 2007 20:54

Re: Verdrehte Bits (Wilde Pointereien)
 
Übrigens verstehe ich auch bei mehrmaligem Lesen des Zitats noch immer, daß man bestimmte Register zwar frei ändern kann, dort steht aber nirgends, daß die automatisch für dich gesichert und wiederhergestellt werden. Also vielleicht doch mal lieber durch einen Disassembler jagen und nachprüfen.

Quake 2. Sep 2007 20:57

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Und genau da irrst du bei einer Funktion, die kein begin/end, sondern asm/end hat. Dort passiert nämlich nichts dergleichen.
Aber da ich mal davon ausgehe, dass die Funktion trotzdem mit einem call oder sowas aufgerufen wird, hättest du trotzdem nichts gewonnen, und irgendwie muss der Wert ja mal in das EAX Register gelangen. Ob ich das jetzt mache, oder Delphi automatisch ist wohl egal.

Die Register müssen nicht gesichert werden, da der Inhalt, der vor dem asm-Block drin war nach dem asm-Block nicht weiter verwendet wird.

Muetze1 2. Sep 2007 21:41

Re: Verdrehte Bits (Wilde Pointereien)
 
Ich möchte hier nur mal passend anmerken, dass man sich auf den oben zitierten Hilfetext zu den zu sichernden Registern nicht verlassen, wenn die Optimierung eingeschaltet ist. Ich habe dadurch schon öfters massive Probleme bekommen, weil die Optimierung zugeschlagen hatte und z.B. EAX auf einmal auch nicht mehr verändert werden durfte (anders gesagt: gesichert werden musste).

Auch vergisst die Hilfe seit je her zu erwähnen, dass man das Direction Flag im Flagsregister möglichst nicht umändern soll. Delphi zeigt da öfters mal die feste Überzeugung, dass niemand anders dieses Flag ändert und von daher setzen viele Codes das Flag nie explizit. (Dieses trifft sogar schon ohne eingeschaltete Optimierung zu!)

Olli 2. Sep 2007 21:41

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

Zitat von Quake
Die Register müssen nicht gesichert werden, da der Inhalt, der vor dem asm-Block drin war nach dem asm-Block nicht weiter verwendet wird.

Hallo? Was ist das denn für ein ausgemachter Unfug? Woher willst du das wissen? Das kann man erst nach einer Analyse in einem Disassembler mit Bestimmtheit sagen und dann auch nur für das aktuelle Kompilat. Kann sich bei einer kleinen Codeänderung schon gewaltig ändern.

Zitat:

Im Allgemeinen sind die Regeln für die Verwendung von Registern in einer asm-Anweisung identisch mit denjenigen für eine external-Prozedur oder -Funktion. In einer asm-Anweisung muss der Inhalt der Register EDI, ESI, ESP, EBP und EBX erhalten bleiben, während die Register EAX, ECX und EDX beliebig geändert werden können. Beim Eintritt in eine asm-Anweisung zeigt EBP auf den aktuellen Stackframe, ESP auf den Beginn des Stacks. Zu Beginn der Ausführung einer asm-Anweisung ist der Registerinhalt unbekannt. Eine Ausnahme bilden die Register ESP und EBP.
Da steht exakt drin:
1. "EDI, ESI, ESP, EBP und EBX" keinesfalls antatschen
2. "EAX, ECX und EDX" darfst du.
3. Der zweite rote Teil suggeriert, daß du sehr wohl die Register (aus 2.) sichern mußt.

Man kann es nicht deutlich genug machen. Der Text besagt nichts darüber, wie die Werte vor oder nach dem asm-Block sind oder sein sollen, sondern wie sie innerhalb des Blocks zu sein haben.

BTW: #18 fand ich einfach goldig :mrgreen: :mrgreen: :mrgreen:

Quake 2. Sep 2007 22:22

Re: Verdrehte Bits (Wilde Pointereien)
 
Ok, ich denke wir sind an einem Punkt, der viel Interprätations Spielraum lässt.

Zitat:

Zu Beginn der Ausführung einer asm-Anweisung ist der Registerinhalt unbekannt.
Das bedeutet für mich:
1. Du kannst dich nicht darauf verlassen, dass z.B. in EAX schon ein bestimmter Wert steht. Das mache ich auch nicht, da ich EAX einen Wert im asm-Block zuweise.
2. Du kannst dich nicht darauf verlassen, dass wenn du den Wert in EAX später noch brauchst, dass er dann noch in EAX steht. Mache ich auch nicht, da ich EAX nur innerhalb des asm-Block verwende.
3. Es muss nicht gesichert werden.

Gut, wenn jetzt in der Onlinehilfe Müll steht, kann ich natürlich nichts machen.

Zu deinem 1. : Du darfst sie schon antasten, nur dann vorher sichern.

Olli 2. Sep 2007 22:46

Re: Verdrehte Bits (Wilde Pointereien)
 
Ich gebe mich geschlagen.

OlafSt 3. Sep 2007 12:41

Re: Verdrehte Bits (Wilde Pointereien)
 
In der OH ist klar erwähnt, wie Parameter übergeben werden und wie Ergebnisse zurückkommen müssen. Der erste Parameter ist IMMER in EAX (außer bei Methodenaufrufen, wie schon erwähnt), Results werden IMMER in EAX zurückgegeben (bei 32-Bit-Werten).

Also ist das bisher gepostete
Delphi-Quellcode:
function SwapBytes (Source: DWORD): DWORD;
asm
  // This is not written as mnemonics to be compatible with D4!
  db 0Fh, 0C8h      // "bswap EAX" can only be executed on 486+!!!
end;
das kürzest- und schnellstmögliche Konstrukt. Wenn das ganze in einer Methode verpack ist, genügt eine weitere Zeile:

Delphi-Quellcode:
function TMyObject.SwapBytes (Source: DWORD): DWORD;
asm
  mov eax,edx
  db 0Fh, 0C8h
end;
Ab Delphi 2006 kann man anstelle des "db 0Fh, 0C8h" auch direkt "BSWAP" schreiben.

Quake 3. Sep 2007 15:03

Re: Verdrehte Bits (Wilde Pointereien)
 
Zitat:

das kürzest- und schnellstmögliche Konstrukt.
Nur weil du in deinen Code kein "mov eax,irgendwas" schreibst heist es noch lange nicht, dass Delphi dies nicht automatisch hinzufügt. Nochmal, was meinst du woher der Wert im EAX Register kommt? Ohne Befehl kann der Wert nicht im EAX Register landen, ob nun von dir hinzugefügt oder von Delphi automatisch.

Zitat:

Ab Delphi 2006 kann man anstelle des "db 0Fh, 0C8h" auch direkt "BSWAP" schreiben.
Mein Delphi 7 kann das auch schon.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:42 Uhr.
Seite 1 von 2  1 2      

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