![]() |
Findfirst/Findnext in Assembler
Hi,
hat jemand ein Findfirst/Findnext Beispiel in Assembler? Bin gerade dabei mir die Grundfunktionen anzueignen und bräuchte daher dieses Beispiel in REINEM Assembler. Insbesondere müsste ich wissen, wie die Information der Dateiattribute aufgebaut ist, die an den Register übergeben wird. Ein Beispiel, welches einfach alle Dateien (*.*) im aktuellen Ordner sucht, und mir deren Namen auf den Stack pushed, wäre gut. :gruebel: Danke. |
Re: Findfirst/Findnext in Assembler
Warum benötigst du dies in Assembler ?
Jeder Compiler wie Delphi/C wird genau so guten Assembler compilieren wie der Mensch. Das liegt daran das bei einer FindFirst()/FindNext() Schleife du nicht viele Möglichkeiten hast durch manuellen Assembler was zu verbessern. Erzeuge einen Delphi Source, compiliere ihn, setze Breakpoint auf erste Quelltestzeile, starte dann Anwendung. Wenn am Breakpoint gehalten wird öffne den CPU View der IDE und nun kannste dir den Machinencode anschauen. Du wirst sehen das eine FindFirst() FindNext() Schleife fast nur aus CALL's zu API Funktionen besteht. Somit wird die Performance dieser Schleife fast nur durchs API bestimmt. Da du auch in Assembler diese CALL's nutzen musst bringt dieser keiner bessere Performance. Zudem, in Delphi/C kannste mit geschützen Codeblöcken arbeiten, sprich try finally usw. Das geht auch in Assembler aber du kannst dann nicht mehr so einfach die try finally's vom Delphi benutzen. D.h. in Deinem Beispiel bingt Assembler keine Vorteile, nur Nachteile bei der Wartung der Source. Gruß Hagen |
Re: Findfirst/Findnext in Assembler
Danke für Deine Mühe, aber das mit Delphi etc, bringt mir nichts, da
ich dabei bin ASSEMBLER zu lernen und daher NICHT den einfachen Weg durch Delphi gehen möchte. Es geht auch nicht um das Sparen von Ressourcen. Ich werde aber mal die Breakpoints setzten und mir die Register ansehen. Dankeschön :coder: |
Re: Findfirst/Findnext in Assembler
Moin Dannyboy,
dann würde es sich allerdings anbieten, wenn Du Dich, zur Übung, mal damit beschäftigst, beispielsweise StringFunktionen wie StringReplace oder Copy in Assembler zu erstellen. Das dürfte als Übung, und auch anschliessend, mehr bringen, als Register für den Aufruf von Betriebssystemfunktionen vorzubereiten. Ein kleines Beispiel findest Du auch hier in der Code-Library. Dort hat sakura eine erweiterte Pos-Funktion reingestellt. |
Re: Findfirst/Findnext in Assembler
Guten Tag Dannyboy,
Da ich selber in Assembler code kann ich dir für den Anfang nur die Tutorials von Iczelion empfehlen. Hier ist ein Link zu seinem Tutorial. ![]() Und als Buch kann ich dir nur das Assembler Buch von Addison Wresley empfehlen. nur als Tip: fang nich gleich mit sowas an. Beschäftige dich erstmal eine Weile mit strings und Stringformatierungen. Was sehr wichtig ist, DER STACK + HEAP :freak: . Wenn du erst einmal gepeilt hast wie der funktioniert hast du schon einiges gut. Just do it ! MfG LB |
Re: Findfirst/Findnext in Assembler
Ja, so'n paar Stack Sachen hab' ich schon gepushed und "gepoppt". :wink:
Ich habe mir mal diese Liste der Interrupts besorgt, da steht so viel drin ... Ja, vielleicht habt ihr Recht. Ich versuche nun mal ein kleines Quicksort mit ASM zu schreiben. In dem integrierten Asm von Pascal habe ich das schon realisiert, weil ich da sowieso das Array, welches sortiert werden muss, in der VAR-Dekla von Pascal deklariere. Ich weiss nicht, wie man ein Array in reinem Asm definiert, aber das kriege ich schon hin. Ich werde dann mal ein wenig „tief stapeln“ und mit ein paar Stack Operationen weiter machen. Thx, boyz |
Re: Findfirst/Findnext in Assembler
Guten Tag,
Wie jetzt ? du machst noch nichmal reines ASM ? nur son Mix aus Pascal und Asm ? Das ist ja quatsch, find ich. Aber naja muss jeder selber wissen. Und wie ich ejtzt mitbekommen habe machst du 16 bit asm. Tja da helfen dir die Tuts auch nciht allzu viel. Na gut, dann push mal weiter. ;) MfG LB |
Re: Findfirst/Findnext in Assembler
Zitat:
Code:
var MyArray: array[0..9] of DWORD
MyArray DD 10 DUP (?) Du wirst die Interrupts aber hoffentlich nicht in einem Win32 Programm verwenden. |
Re: Findfirst/Findnext in Assembler
Zitat:
Wenn ich dir meine 250.000 Zeilen Anwendung maile und du solltest sie in Assembler umsetzen, dann geht das nicht in entsprechender Zeit. Gruß Hagen |
Re: Findfirst/Findnext in Assembler
Guten Tag Hagen,
also ich programiere ASM nicht um irgendwelche Riesenprogramme zu schreiben sondern aus verschiedenen Gründen: - Copy & Paste aus IDA (Disassembler) - Geringe Filesize (10 kb) - ist einfach geil Ok, ich mein mal von der Filesize ausgehend ist es für mich schwachsinn z.B. in Delphi ASM zu integrieren. Da ja trodzdem 400 KB rauskommen. Ich bin halt ein kleiner Größenfetischist. :coder: MfG LB |
Re: Findfirst/Findnext in Assembler
Zitat:
Aus Sicht der Ökonomie ist aber Assembler nur hilfreich wenn es um Spezialprobleme geht die nicht durch den Compiler lösbar sind. Nur bei solchen Problemen kann ein Asselbersource 200-1000% mehr Leistung bringen. Da aber die meisten Programmierer nicht so wie WIR sind, ist es besser von vornherein darauf hinzuweisen das Assembler effektiv viel Zeit und Wissen kostet und wirklich nicht viel bringt. Speicher ist cheap, und demzufolge ist es relativ unwichtig ob eine EXE 20Kb oder 400Kb groß ist. Nur bei der Programmierung von Viren usw. ist es tatsächlich wichtig enorm kurze Programme zu schreiben. Allerdings die 400Kb eines Delphiprogrammes kommen nicht von einem schlechten Compiler, sondern von der VCL. Man kann also mit Delphi, nach Änderung der Unit System/SysUtils auf's Minimum, ebenfalls Programme schreiben die nur 8-14Kb groß sind. Kleiner gehts dann nur mit COM Files, da bei EXE's das PE Fileformat die minimale Größe vorgibt. Ich glaube Luckie und ich hatten mal darüber eine Diskussion. Gruß Hagen |
Re: Findfirst/Findnext in Assembler
Das Problem ist bei mir! Ich habe im "guten alten" (denkste :) ) DOS kleine COM Anwendungen geschrieben (meist TSR sachen) und auf nemm 80535 glaube ich in der Schule. Doch Dummerweise kann ich die erfahrungen nicht auf den Inline-Assambler anwenden. Daher ich geben auf! *schnief*
|
Re: Findfirst/Findnext in Assembler
Guten Tag Hagen,
Jo das es vie Zeit kostet weiß ich aber es macht irgendwie Spaß. Ich hatte mal einen Bildviewer in ASM programmiert. Das selbe nochmal in Delphi. Und die Effektitivtät ist echt beraubend. Das waren mehrere tausen Zeilen in ASM und wenige hundert in Delphi. Naja also ich mache fast alles nur in Delphi außer keymakers oder ähnliches. Von daher stimme ich dir zu. MFG LB |
Re: Findfirst/Findnext in Assembler
Zitat:
Zitat:
|
Re: Findfirst/Findnext in Assembler
Zitat:
Uebrigens, mit Modifikation der System-Units bringt man es mit Delphi auf minimal 3,5 kB! (Aber dann kann man auch gleich nen Assembler mit HLL-Syntax nehmen, wie zB MASM). Assembler ist fuer einzelne Sachen immer mal wieder wichtig ... zB wenn man Bytes in einem DWORD drehen will (BSWAP in ASM) dann ist das mit Delphi allein sehr umstaendlich. Fuer meine Implementation in der TScreenShotClass habe ich aber genau das benoetigt, und dann eben den groessten Teil einer ganzen Schleife gleich in ASM verfasst. Bei Bildverarbeitung ist Performanz immer noch eine wichtige Sache! |
Re: Findfirst/Findnext in Assembler
@Assarbad: Die größten Probleme sind die Parameter und der Result.
Delphi-Quellcode:
Ganz leicht aber Funktiuoniert nicht. Und genau hier hab ich die Segel gestreift.
procedure _Swap(var a, b : Cardinal);
asm mov eax, [a] mov ebx, [b] mov [a], ebx // <- Zugriffsverletzung mov [b], eax end; |
Re: Findfirst/Findnext in Assembler
Delphi-Quellcode:
Überlege dir mal wie der Delphi Compiler der procedure _Swap die Paramter übergibt !
procedure _Swap(var a, b : Cardinal);
asm mov eax, [a] mov ebx, [b] mov [a], ebx // <- Zugriffsverletzung mov [b], eax end
Delphi-Quellcode:
Wie du oben siehst wird A in EAX und B in EDX übergeben. Dein Zugriff mit MOV EAX,[a] -> MOV EAX,[EAX] überschreibt also die Adresse von A mit dem Wert in Adresse A, etwa so MOV A,[A].
procedure _Swap(var a {EAX}, b {EDX} : Cardinal); {register}
asm PUSH EBX // mov eax, [a] MOV EAX,[EAX] // mov ebx, [b] MOV EBX,[EDX] // mov [a], ebx // <- Zugriffsverletzung MOV [EAX],EBX // mov [b], eax MOV [EDX],EAX POP EBX end Zudem nutzt du register EBX in deiner Funtion OHNE es zu sichern. Ließ die Delphi Hilfe, die besagt das nur EAX,EDX,ECX im Assemblersource frei benutzt werden können. D.h. EAX,EDX,ECX müssten nicht gesichert werden, alle anderen Register wie EBX,EDI,ESI,EBP aber schon.
Delphi-Quellcode:
Gruß Hagen
procedure Swap(var A,B: Cardinal);
asm MOV ECX,[A] XCHG ECX,[B] MOV [A],ECX end; //oder procedure Swap(var A,B: Cardinal); asm PUSH DWord Ptr [A] PUSH DWord Ptr [B] POP DWord Ptr [A] POP DWord Ptr [B] end; // oder procedure Swap(var A,B: Cardinal); asm PUSH EBX MOV ECX,[A] MOV EBX,[B] MOV [B],ECX MOV [A],EBX POP EBX end; |
Re: Findfirst/Findnext in Assembler
Kurz und auf den Punkt!
Danke! Werde darauf aufbauen. |
Re: Findfirst/Findnext in Assembler
Kurz und auf den Punkt!
Danke! Werde darauf aufbauen. EDIT: Man war ich blöd! |
Re: Findfirst/Findnext in Assembler
Hi,
ich habe da mal eine Zwischenfrage. Kann mir jemand mal ein klassisches Beispiel für den Einsatz von ASM geben ? Also wo es sich gegenüber Delphi Programmierung wirklich sichtbar auswirkt ? Nicht mit 10 % und so. Ich habe nämlich noch nie einen zwingenden Grund gesehen, daß es anders nicht zumindest akzeptabel gehen sollte. Performanceprobleme kommen doch eher von anderer Seite, z.B. Dateigrößen, die nicht auf das Windows-Dateisystem abgestimmt sind. Datenbanken mit schlecht entworfenen Indices, usw. Was mehr oder weniger die Festplatten betrifft. Oder Sortierungen, die unnötig zuviel sortieren, falsche Schleifen, die zu lange laufen, was dann eher den Hauptspeicher betrifft. Was kann ich da mit einer von Hand zu Fuß Verschiebung der Register noch spürbar ausgleichen ? Ich wurde mal gezwungen einen 8 Bit DEC-Prozessor (ohne PC, wohlgemerkt) zu programmieren. Nicht mal in ASM sondern sogar in Oktal-Code, also ohne Mnemonics. Der hatte sogar noch Spezialbefehle und war inkompatibel. Wer macht denn sowas freiwillig ? Mir gruselts heute noch. Vor allem, da der Compiler von sich aus schon viel optimiert und bei einer Division durch 2 glaube SHR ??? ausführt und keine real-Operation. So ein klassisches Beispiel, mit Erklärung hat doch bestimmt jemand ? |
Re: Findfirst/Findnext in Assembler
Ein Bsp. kann ich nicht bringen.
Schaut man sich aber den Source von den Delphi Units an so wurde sehr oft Assembler durch Pascal ersetzt. |
Re: Findfirst/Findnext in Assembler
Delphi-Quellcode:
function SwapBytes(Value: Cardinal): Cardinal;
asm BSWAP EAX end; function SwapBytes(Value: Cardinal): Cardinal; begin Result := (Value shr 24) or (Value shr 8) and $0000FF00 or (Value shl 8) and $00FF0000 or (Value shl 24) end; function CountBits(Value: Cardinal): Integer; begin Result := 0; while Value <> 0 do begin if Odd(Value) then Inc(Result); Value := Value shr 1; end; end; function CountBits(Value: Cardinal): Integer; asm MOV EDX,EAX SHR EDX,1 AND EDX,055555555h SUB EAX,EDX MOV EDX,EAX AND EAX,033333333h SHR EDX,2 AND EDX,033333333h ADD EAX,EDX MOV EDX,EAX SHR EDX,4 ADD EAX,EDX AND EAX,00F0F0F0Fh MOV EDX,EAX SHR EDX,8 ADD EAX,EDX MOV EDX,EAX SHR EDX,16 ADD EAX,EDX AND EAX,0FFh end; |
Re: Findfirst/Findnext in Assembler
Zitat:
|
Re: Findfirst/Findnext in Assembler
Zitat:
Gruß Hagen |
Re: Findfirst/Findnext in Assembler
Aus Classes.pas
Delphi-Quellcode:
procedure BinToHex(Buffer, Text: PChar; BufSize: Integer); assembler;
const Convert: array[0..15] of Char = '0123456789ABCDEF'; var I: Integer; begin for I := 0 to BufSize - 1 do begin Text[0] := Convert[Byte(Buffer[I]) shr 4]; Text[1] := Convert[Byte(Buffer[I]) and $F]; Inc(Text, 2); end; end; {asm PUSH ESI PUSH EDI MOV ESI,EAX MOV EDI,EDX MOV EDX,0 JMP @@1 @@0: DB '0123456789ABCDEF' @@1: LODSB MOV DL,AL AND DL,0FH MOV AH,@@0.Byte[EDX] MOV DL,AL SHR DL,4 MOV AL,@@0.Byte[EDX] STOSW DEC ECX JNE @@1 POP EDI POP ESI end;} function HexToBin(Text, Buffer: PChar; BufSize: Integer): Integer; assembler; const Convert: array['0'..'f'] of SmallInt = ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,10,11,12,13,14,15); var I: Integer; begin I := BufSize; while I > 0 do begin if not (Text[0] in ['0'..'f']) or not (Text[1] in ['0'..'f']) then Break; Buffer[0] := Char((Convert[Text[0]] shl 4) + Convert[Text[1]]); Inc(Buffer); Inc(Text, 2); Dec(I); end; Result := BufSize - I; end; {asm PUSH ESI PUSH EDI PUSH EBX MOV ESI,EAX MOV EDI,EDX MOV EBX,EDX MOV EDX,0 JMP @@1 @@0: DB 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 DB -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 DB -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 DB -1,10,11,12,13,14,15 @@1: LODSW CMP AL,'0' JB @@2 CMP AL,'f' JA @@2 MOV DL,AL MOV AL,@@0.Byte[EDX-'0'] CMP AL,-1 JE @@2 SHL AL,4 CMP AH,'0' JB @@2 CMP AH,'f' JA @@2 MOV DL,AH MOV AH,@@0.Byte[EDX-'0'] CMP AH,-1 JE @@2 OR AL,AH STOSB DEC ECX JNE @@1 @@2: MOV EAX,EDI SUB EAX,EBX POP EBX POP EDI POP ESI end;} |
Re: Findfirst/Findnext in Assembler
Zitat:
|
Re: Findfirst/Findnext in Assembler
Tja, falsch gedacht. Das Problem bei Kylix ist das Register EBX. Auf Windows Maschinen ist dieses Register "unbenutzt" d.h. man kann es frei verwenden. Delphis Compiler hat per Definition EAX,EDX,ECX als vollständig freie Register defeiniert und EBX,ESI,EDI als teilfreie Register deren Inhalt in ASM gesichert werden muß. Register EBP ist bei ASM Sourcen der Basepointer auf eventuelle Paramter oder lokale Daten. Man kann dieses Register aber ebenfalls benutzen wenn man die Regeln beachtet.
Nun, in Kylix enthält das Register EBX die GOT = Global Object Table. Diese Tabelle ist sowas ähnliches wie das Datensegement. ALLE globalen Daten werden immer über Register EBX referenziert ! D.h. das Betriebssystem kann die Daten einer Anwendung dynamsich und zu jeder Zeit durch Änderung der GOT in EBX im Speicher veschieben. Dadurch soll das Speichermanagement des OS verbessert werden. Nun, dies stimmt auch bringt aber nicht so viel. Da nun beim Überschreiben von EBX der Zeiger auf die GOT zerstört wird wird das Program abstürtzen. Denn, auf meine Anfragen bei Borland, wie sich das Exceptionhandling von Kylix verhält wenn EBX überschriben wurde, warte ich noch heute. Da aber der Exceptionhandler selber auf die GOT in EBX angewiesen ist, würde eine Überschreiben von EBX eine Exception auslösen (im spärteren Programteilen) und der Excpetionhandler ebenfalls eine Exception auslösen usw. usw. Somit darf EBX NIEMALS überschriben werden in Kylix. Um dies zu verhindern entschlossen sich die Borland-Programmierer das der Compiler darauf zu achten hat das EBX unverändert bleibt. Somit musste jeder Assemblersource erstmal als PASCAL vorliegen. Denn nur dann hat auch der Compiler die Gewalt darüber. Es ist also aus Zeitgründen einfacher alle Assemblerparts in PASCAL Source zu ändern. Dann kann durch Änderungen am Compiler selber das korrekte Verhalten mit der GOT besser kontroliert werden. All diese Änderungen bewirken das in großen Teilen bestehender und guter Assembler ersetzt wurde. Da der Compiler selber auch noch schlchter wurde, ist es klar das die Gesamtperformance der Compilate darunter zu leiden hatte. Ich will hier NICHT auf die Kylix Gemeinde schimpfen o.ä. die können am wenigsten dafür. Aber es dürfte nun klarer werden was Kylix für die Windows-Gemeinde für Auswirkungen hatte. Gruß Hagen |
Re: Findfirst/Findnext in Assembler
haha, da machen die einem ja schön vor, wie mans nicht machen sollte. Und da ich mich schon immer an die eisernen Regeln gehalten habe, niemals Hardware/betriebssystemnah zu coden, laufen sogar noch meine alten DOS Programme unter XP problemlos. Ich schimpfe auch nicht auf Kylix, aber da haben die sich was schönes eingebrockt. Das da ist nicht der einzige Grund. Mich ärgert alleine schon, daß in der OH alles doppelt kommt und CLX immer oben steht. :mrgreen:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:01 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