Stringsuche in assembler



  • Moin erst mal,
    ich hab folgendes Problem, ich soll in Tasm ein Programm schreiben welches eine Stringsuche in einer Datei macht. Ich hab aber keinen Plan wie ich diese suche machen soll da Assembler für mich Neuland ist, bis jetzt hab ich die abfrage für den zu suchenden String und das öffnen der Textdatei was auch bei soweit klappt aber nun ist Ende mit meinem Latein.

    Ich hoffe das mir jemand weiter helfen kann und dafür schon mal danke im Voraus.



  • schau mal hier: http://www.henkessoft.de/OS_Dev/OS_Dev1.htm#mozTocId97419
    Da werden eingegebene Texte auf Übereinstimmung mit vorhandenen Befehlen vergleichen. Vielleicht hilft Dir das weiter.

    strcmp:
    .loop:
      mov al, [si]   ; fetch a byte from SI
      cmp al, [di]   ; are SI and DI equal?
      jne .done      ; if no, we're done.
    
      or al, al      ; zero?
      jz .done       ; if yes, we're done.
    
      inc di         ; increment DI
      inc si         ; increment SI
      jmp .loop      ; goto .loop
    
    .done:    
      ret
    


  • So momentan hab ich zwar nen vergleich doch irgendwie funktioniert dieser auch nicht meine Vermutung ist das das Problem hierbei ist das er die komplette Textdatei als ein String an sieht und somit nicht mit Suchstring überein stimmt ich poste einfach mal meinen Quelltext hinzu vielleicht hat jemand ja die Lösung für mein Problem denn ich bin am verzweifel.

    Bitte nicht all zu kritisch mit dem bisher geschriebenen ich hab mit Tasm erst vor 3 Wochen anfangen(müssen) und habe vorher noch nix damit zu tun gehabt ist jetzt halt Studien relevant.

    Danke im Voraus und ein Dankeschön @Erhard Henkes

    ;******************************************
    ;*				 	  	    *
    ;*Aufgab: Stringsuche in einer Textdatei*
    ;*				 	          *
    ;******************************************
    TITLE TEST
    
    .Model Small
    .Stack 500h
    ;**********************************************
    ;*************Macros***************************
    ;**********************************************
    printe	Macro Z
    		MOV DX,Offset Z
    		MOV AH,09H
    		INT 21h
    		EndM
    ;
    ;
    ;
    ;*********************************************
    ;************DATA*****************************
    ;*********************************************
    .Data
    ;**************programminfo********************
    pinfor db "Programm zur Suche eines String in einer Datei",10,13,"$"
    ;
    ;*************String***************************
    sinfor db "Bitte geben sie ihr Suchstring(bitte maximal 4  Zeichen)",10,13,"$"
    such	db 10 dup(?)
    suchp dw ?
    ;***********Datei******************************
    dinfor db "Bitte Datei eingeben",10,13,"$"		  
    msgs	db 10,13,"geht$"
    msge	db 10,13,"error",10,13,"$"
    eing db 255 dup(?)	  
    filehandle dw ?
    puffer db 255 dup(0)
    
    ; 
    ;
    ;**********************************************
    ;************CODE******************************
    ;**********************************************
    .Code
    ;
    ;
    ;
    ;**********************************************
    ;********Programminformation*******************
    start:	MOV AX,@data
    		MOV DS,AX
    		printe pinfor 
    ;
    ;
    ;
    ;**********************************************
    ;******Ausgabe Infotext Suchstring*************
    string:	MOV AX,@data
    		MOV DS,AX
    		MOV ES,AX		
    		printe sinfor
    ;
    ;
    ;
    ;******Stringeingabe vor Datei*****
    ;
    ;
    		MOV SI,0
    lesen2:	MOV BX,0
    		MOV CX,255
    		MOV DX,OFFSET such
    		MOV AH,03FH
    		INT 21h
    		MOV suchp,AX
    		DEC AX
    		DEC AX
    		MOV SI,AX
    		MOV such[SI],0H
    ;**********************************************
    ;************Ausgabe Infotext Datei************
    datei:	MOV AX,@data
    	  	MOV DS,AX
    		printe dinfor 
    
    ;
    ;
    ;*********Eingabe Tastaturpuffer für Dateinamen*********
    ;
    ;
    		MOV SI,0
    lesen:  	MOV BX,0
    	  	MOV CX,255
    	  	MOV DX,OFFSET eing
    	  	MOV AH,03FH
    	  	INT 21h
    	  	DEC AX
    	  	DEC AX
    	  	MOV SI,AX
    	  	MOV eing[SI],0H
    ;
    ;
    ;*************Öffnen der Datei*********************
    ;
    ;
    open:   	MOV DX,offset eing	  		  	 
    	  	MOV AH,3DH			;Datei öffnen
    	  	MOV AL,0	
    	  	INT 21h
    	  	MOV filehandle,AX
    	  	JNC luck
    	  	JC  pech
    
    luck:	  	printe msgs
    	  	JMP short read
    
    pech:   	printe msge
    	  	JMP datei
    ;************Datei lesen***************************
    ;
    ;	
    read:   	MOV CX,100H
    	  	MOV DX,offset puffer
    	  	MOV BX,filehandle
    	  	MOV AH,3fh
    	  	INT 21h
    ;******vergleichen Inhalt der Datei mit Suchstring***
    ;		
    vgl1:		MOV DI,offset filehandle;auf str1 zeigen
    		MOV SI,offset suchp		; ;auf str2 zeigen
    		MOV CX,4 ;Länge 4
    		REPE CMPSB ;vergleichen
    		JE success ;falls  gleich Sprung
    
    fail:		printe msge
    		JMP short fin
    
    success:	printe msgs
    
    ;
    ;
    ;
    ;
    ;**************************************************
    ;****************ENDE******************************
    ;
    ;	  
    fin:	  	MOV AX,4C00h
    	  	INT 21h
    End start
    ;
    


  • Dein Problem hat nichts damit zu tun, wie du die Datei ansiehst, sondern eher damit, dass du nur die ersten 4 Byte der eingelesenen Datei mit deinem Suchstring vergleichst.
    Wenn du von Assembler keine Ahnung hast, hilft es dir vielleicht, wenn du deinen Code erstmal in einer Hochsprache wie C (natuerlich ohne Verwendung von netten "DurchsucheDatei"-Funktionen) oder Pseudocode formulierst und dann versuchst in Assembler umzusetzen.

    Falls das uebrigens nicht klar sein sollte: "cmpsb" laedt je ein Byte von es:di und ds:si, vergleicht die beiden wie cmp und erhoeht die Register si und di um eins (idR., wenn das DF=0 ist).
    "rep cmpsb" wiederholt das dann entsprechend so lange, bis cx=0 wird, oder die beiden verglichenen Bytes ungleich sind.
    ... Daraus sollte schon klar werden, dass ein Aufruf von "rep cmpsb" nicht reichen kann, um einen Datensatz (zB. eine eingelesene Datei), der laenger als der Suchstring ist, komplett zu durchsuchen.



  • @ Nobuo T danke für den tipp.

    Also kann ich meinen Vergleich weg schmeißen und mir was neues überlegen verdammt ich weis bloß nicht was. Hat jemand nen Tipp oder vielleicht schon mal sowas gemacht weil mir läuft irgendwie die Zeit davon und ich hänge immer noch an der Suche obwohl irgendwie alle sagen das sei nicht so schwer mit Assembler(eindeutig seh ich den Wald vor lauten Bäumen nicht).
    😕 😕 😕 😕 😕 😕 😕



  • Nein, du brauchst deinen Vergleich nicht komplett in die Tonne kloppen, du musst ihn nur erweitern (und hier und da ein wenig korrigieren), so dass der komplette eingelesene Datensatz verglichen wird.

    Wie gesagt: Vielleicht hilft die Sache mal in C-aehnlichem Pseudocode zu betrachten... Was du im Moment hast, sieht im Prinzip so aus:

    char* a = &such;  // Zeile 130 in deinem Code muesstest du zB. noch korrigieren:
    // du brauchst einen Pointer auf den Anfang deines Suchstrings und nicht den Pointer auf "suchp"
    char* b = &puffer;  // dito mit Zeile 131: Du musst den Pointer am Anfang auf die Adresse des Puffers setzen, in den du die Datei eingelesen hast. Mit einem Pointer auf den FileHandle kannst du nichts anfangen
    for (i=4; i>0 && *(a++) == *(b++); i--); // das ist praktisch, was rep cmpsb macht
    // a und b uebernehmen hier also die Aufgabe der Register si und di
    

    Vergleicht genau die ersten 4 Zeichen des Suchstrings und der eingelesenen Datei miteinander...

    Was du aber haben muesstest, um die komplette Datei zu durchsuchen, waere z.B. in etwa sowas hier:

    char* b = &puffer; // Pointer auf den Puffer fuer die Datei
    for (j = 0; j < 0x100 - 4; j++) {
        char* a = &such;
        for (i=4; i>0 && *(a++) == *(b++); i--); // deine aktuelle "rep cmpsb" Suche
        if i = 0 goto gefunden; // wurden alle 4 Zeichen erfolgreich verglichen, hast du den String gefunden.
        b=b-(4-i); // wieder zurueck auf das naechste Zeichen vor Anfang des Vergleichs.
    }
    nicht_gefunden:
    writeln "String nicht gefunden.";
    halt;
    gefunden:
    writeln "String gefunden :-)";
    halt;
    

    Hoffe, das macht es etwas klarer, was noch fehlt.



  • @ Nobuo T

    Also wenn ich das richtig versteh ist das Problem bei meiner momentanen Version das ich die Größe des Strings aus der Textdatei nicht kenne/richtig angebe und nicht sage wo es anfangen und wo aufhören soll zu vergleichen oder?

    Dein Beispiel in C versteh ich ja so halbwegs aber wie ich das in meinen Assembler Programm umsetzen soll weis ich nicht.Und dann noch nen Counter rein zimmer der mir sagt wie oft der String vor kommt( 😕 😕 😕 )

    So schäfft ein Prof. auf der Beliebtheitsskala weit nach unten zu kommen,naja mal sehen ob ich das noch zum laufen bekomme ich glaub nicht mehr dran, sind ja noch drei Tage



  • Irgendwie scheinst du meine C-artigen Codes ja doch nicht so ganz verstanden zu haben...
    Ich kenne deine Vorgaben/Aufgabenstellung nicht, also weiss ich nicht, in wie weit ihr die Groesse der Datei beruecksichtigen sollt. Momentan hast du eine Groessenbeschraenkung auf maximal 256 Byte Dateigroesse in deinem Programm - das ist alles. In meinem Pseudocode werden dann zwar immer die ganzen 256 Byte des Puffers durchsucht, das ist aber hoechstens ineffizient, sonst nicht weiter schlimm.
    Das mit dem "nicht sage[n] wo es anfangen und wo aufhören [...] zu vergleichen" stimmt auch nur halb. Fuer den ersten Durchlauf gibst du ja durchaus (zwar falsche) Adressen fuer die Vergleiche an. Du brauchst eben um deinen "rep cmpsb"-Vergleich noch eine weitere Schleife, die den Anfang des Vergleichs in der Datei immer Byte-weise nach hinten verschiebt.

    Mach doch wirklich erstmal einen groben Pseudo-Code-Entwurf fuer dein Programm und dir daran klar, wie die Suche funktioniert. Die Umsetzung in Assembler sollte dann relativ einfach und systematisch moeglich sein.

    PS:
    Ueber den Prof poebeln ist schoen und gut - bringt dich aber zum einen erstmal nicht weiter und zum anderen sind so grundlegende Dinge wie grundlegendes Verstaendnis von Algorithmen und Programmiersprachen (wo es bei dir scheinbar noch hapert) wirklich etwas, was in einer Uni-Vorlesung iAR. einfach vorausgesetzt wird. Wenn du da jetzt in Probleme rennst, solltest du dir auch ein bissel mal an die eigene Nase packen. 😉



  • Dein Beispiel in C versteh ich ja so halbwegs aber wie ich das in meinen Assembler Programm umsetzen soll weis ich nicht.Und dann noch nen Counter rein zimmer der mir sagt wie oft der String vor kommt( 😕 😕 😕 )

    Du könntest den C-Code durch einen Compiler umsetzen lassen und Dir den resultierenden Assemblercode schrittweise vergleichend mit objdump (GNU binutils) anschauen, wenn Du es nicht selbst schaffst. Nur so als Idee.



  • Will Dir, allerdings mit 32 Bit Inline-Assembler in einem C-Programm, zeigen, wie man eine Suche mittels repe cmpsb und folgendem jecxz durchführen kann.

    #include <stdio.h>
    
    #define	STR 3
    
    int main(void)
    {
    	char buf[] = "Hallo, wie geht es Dir?";
    	char suchstring[STR+1] = "wie";
    	int* Adresse  = NULL;
    	int  Position;
    	__asm
    	{
    		lea		esi, buf
    L1:
    		push    esi
    		lea     edi, suchstring
    		mov     ecx, STR
    		repe    cmpsb
    		jecxz   Uebereinstimmung
    		pop     esi
    		inc     esi
    		or      byte ptr [esi+STR], 0
    		jnz     L1
    		jmp     Ende
    Uebereinstimmung:  
    		pop     Adresse
    		mov     esi, Adresse
    		lea     edi, buf
    		sub     esi, edi
    		mov     Position, esi     
    Ende:
    	}
    	if (Adresse)
    		printf("Suche erfolgreich an Position %d\n", Position);
    
    	return 0;
    }
    

    Bei 16 Bit Programmierung ändern sich die Registerbezeichnungen und aus jecxz wird jcxz .

    mfg


Anmelden zum Antworten