[TASM] Sortieren eines Array funktioniert nicht richtig



  • Ich brauche wieder Hilfe bei Assembler

    Es sollen Elemente sortiert und aufsteigend ausgegeben werden. Ich habe das mit Countingsort gemacht. Allerdings zeigt er dann ins Nirvana. Wenn ich den Stack nicht imlementiere, erscheint eine Warnung, dass kein Stack da ist. Ich glaube aber, dass das nicht unbedingt wichtig ist.

    .model small
    ;.stack 100h
    org 100h
    .data
    len db 0
    array db 255 dup(0)
    count db 256 dup(0)
    
    jumps
    .code
    start:
    
    mov ax,@DATA
    mov ds,ax
    
    ;Eingabe
    mov ah,0ah
    mov dx,offset array-2
    int 21h
    
    ;Sortierung mit Hilfe des Countingsort
    
    xor si,si
    xor ax,ax
    mov al,[len]
    sort:
    
    xor bx,bx
    mov bl,byte ptr [array+si]
    
    inc   [count+bx]
    inc   si
    cmp   si,ax
    jne   sort
    
    xor si,si
    mov di,offset array
    
    how:
    
    xor cx,cx
    mov cl,[count+si]
    
    test cx,cx
    jz increm
    
    mov   ax,si
    rep   stosb
    
    increm:
    inc   si
    cmp   si,256
    jne how
    mov byte ptr es:[di],'$'
    
    ;Ausgabe des Arrays
    mov ah,9
    mov dx,offset array
    int 21h
    
    mov ah,7
    int 21h
    cmp al,1
    jnz quit
    quit:
    mov ah,4ch
    int 21h
    ret
    end start
    


  • 1. Die Funktion 0Ah des Interrupts 21h braucht zwei Werte am Anfang des Eingabepuffers:

    maxlen db 254
    len db 0
    array db 255 dup(0)
    

    2. Der Befehl 'rep stosb' schreibt einen Block nach ES:DI. Du musst also noch ES initialisieren:

    mov ax,@DATA
    mov ds,ax
    mov es,ax
    

    Nach meinen groben Tests funktioniert es dann.

    Die Sache mit dem Stack ist hier nicht wichtig, da er nicht benutzt wird. Du solltest ihn aber auf jeden Fall einrichten, sonst gibt es unerklärliche Effekte, wenn mal auf ihn zugegriffen wird.

    viele grüße
    ralph



  • dedmazay schrieb:

    Ich brauche wieder Hilfe bei Assembler

    Wie wäre es aber erstmal mit einem Blick mit dem Debugger? 😉

    mov ah,0ah
    mov dx,offset array-2
    int 21h
    

    Nicht gerade sehr aussagekräfig bei dieser Funktion. Was geht hier vor?
    Ein Blick auf den Datendump hilfreich...
    (und wer kein Interrupt Handbuch dabei hat, versteht das vielleicht auch nicht gleich sofort, z.B. wenn man ein Jahr später wieder draufguckt...)

    dedmazay schrieb:

    mov bl,byte ptr [array+si]
    

    Kann bl eigentlich auch word ptrs aufnehmen oder tbyte ptrs ?

    dedmazay schrieb:

    inc   [count+bx]
    inc   si
    cmp   si,ax
    

    Es ginge auch inc ah, bzw. cmp ah,al, da ja mit bytes gearbeitet wird...aber wie das jetzt handlen?
    Z.B. ginge ja sowas wie

    mov cl,[len]
    mov bx,count ;aber (Count) mit Alignement, sonst gibts eventuell einen ;Überlauf...
    ;oder man nimmt lea wenn es zusätzlich noch was zu rechnen gibt.
    repl:
    cmp al,0dh ;wegen der Interruptfunktion 0A, die am Ende des Strings 0Dh setzt.
    jz out 
    lodsb ;byte von DS:SI nach al, si=si+1
    add bl,al ;der Zeiger auf den Hilfsarray (Count), für die statistische Datenerfassung
    inc [bl]    ;Statistik
    sub bl,al 
    loop repl
    

    Und wenn man später wieder von hinten anfängt, braucht man nur die Direction verändern, und Si wird wieder heruntergezählt

    Aufsummieren:

    ;den Wert in Si um 1 vermindern
    ;oder irgendwas mit cl rechnen, wegen dem
    ;Aufsummier-Loop 1 weniger wegen
    ;den ersten Bytes, die vor dem Loop aufsummiert werden.
    mov cx,si
    sub cx,1
    ;und jetzt müsste man sowas machen können wie 
    add [bl],[bx-1]; aber das geht überhaupt nicht, shit ! ;)
    ;also...
    mov al,[bx] ;oder ...*count...
    inc bl
    add [bx],al
    loop
    

    dedmazay schrieb:

    increm:
    inc   si
    cmp   si,256
    jne how
    mov byte ptr es:[di],'$'
    

    hier kann man sich das auch etwas einfacher machen, wir haben ja noch die Länge der 0Ah Interruptfunktion

    dedmazay schrieb:

    mov ah,7
    int 21h
    cmp al,1
    jnz quit
    quit:
    mov ah,4ch
    int 21h
    ret
    end start
    

    Und was soll das? Und was hat der ret Befehl da unten zu suchen? Der macht vermutlich auch Ärger 😉

    Ganz allgemein: bei org 100h kann man ein .Com Programm erstellen, und braucht keine Segmenteinrichtung. Aber falls man die doch braucht, kann man sogar selber machen, allerdings braucht es dafür ein besseres Verständnis vom Real Mode.

    fasm http://www.flatassembler.net/ macht es in dieser Phase recht einfach, einfach org 100h und assembliert den Code zum Com-Proggie. Auch directx Programmierung geht damit sehr gut.

    Falls man das Programm später nochmal anguckt, dann ist eine Strukturierung, Kommentierung und aussagefähige Variablen usw. hilfreich
    Man braucht für Funktion 0Dh vom Interrupt 21 2 Bytes (vorne) für Maximaleingabe (Max) und tatsächlichen gezählten Eingabebytes, hat ja rkhb auch schon gepostet.

    Statt array hätte man Inputstring und Outputstring oder "new order" schreiben können, um zu strukturieren bzw. Jahre später noch zu erkennen, was man eigentlich gemacht hatte.

    Naja, und Windowsprogramme/Dosfenster kann man zum Teil mit der Maus so einstellen, dass sie offen bleiben, oder man bleibt gleich in der Konsole, schreibt z.B. mit Konsoleneditor wie dem Vi von Watcom und dann guckt man sich mit debug an, wie was läuft. Und man könnte auch im Programm selber transparent fragen: "nochmal?"
    😉

    Bei Com Programmen gibt es übrigens nur (typischerweise) nur ein Segement (wie bei Windows eigentlich auch), so gesehen braucht man keinen stack. Dass Assembler (masm) darauf hinweisen, dass kein Stack da ist (nur ein Segment), ist ganz normal, aber keine Fehlermeldung.



  • nachtfeuer schrieb:

    dedmazay schrieb:

    mov bl,byte ptr [array+si]
    

    Kann bl eigentlich auch word ptrs aufnehmen oder tbyte ptrs ?

    Das geht mit bl nicht und deswegen genügt hier auch ein:

    mov bl, [array+si]"
    

    [quote="dedmazay"]

    inc   [count+bx]
    

    Aber weil der Assembler in diesem Fall es nicht genau wissen kann, ob auf ein Byte, Word, oder DWORD zugegriffen werden soll, deswegen müssen wir es hier mit angeben.

    inc word ptr[count+bx]
    

    Dirk



  • freecrac schrieb:

    Aber weil der Assembler in diesem Fall es nicht genau wissen kann, ob auf ein Byte, Word, oder DWORD zugegriffen werden soll, deswegen müssen wir es hier mit angeben.

    inc word ptr[count+bx]
    

    Hier sinnvollerweise mit byte ptr, aber man kann gerade als Anfänger/Mitleser an dieser Stelle wegen den zwei Zeigern auf Zahlen und Statistik und wegen den unterschiedlichen Registergrößen durcheinanderkommen. 😉


Anmelden zum Antworten