Direkte und Indirekte Adressierung



  • Hallo zusammen
    Ich bin seit einigen Tagen dabei, Assembler zu erlernen und leider tauchen dabei immer wieder neue Fragen auf, welche mir mein Lehrer nicht beantworten kann!

    Ich versuche gerade, die Varianten der direkten und indirekten Adressierung zu erlernen und habe mir in diesem Zusammenhang ein kleiner Beispielcode geschrieben.

    Leider funktioniert dieser Code nicht wo, wie ich es erwartet hätte, wie könnte es auch anders sein... 😃

    Ich habe hinter jede Instruktion in einem Kommentar geschrieben, was ich glaube zu wissen, was die entsprechende Zeile tut. Diese Formulierung ist absichtlich, weil das Programm ja offensichtlich nicht das tut, was ich glaube zu wissen.

    .MODEL SMALL
    
    .DATA
    Arr  DB 3 DUP(0) ; 3 Bytes speicher reservieren
    pArr DW ?        ; 2 Bytes für die 16-Bit Speicheradresse von Arr zu speichern
    
    .CODE
    START: mov ax,@Data ; Basisadresse vom Datensegment in ax speichern
           mov ds,ax    ; Basisadresse in Datensegment register speichern
    
           mov Arr,"S"     ; Den Wert ASCII "S" in Adresse von Arr speichern
           mov [Arr+1],"a" ; Den Wert ASCII "a" in Adresse von Arr+1 speichern
           mov [Arr+2],"m" ; Den Wert ASCII "m" in Adresse von Arr+2 speichern
    
           lea ax,Arr  ; die effektive Adresse von Arr ins ax register speichern
           add ax,02h  ; adresse, welche in ax gespeichert ist mit 2 inkrementieren
           mov pArr,ax ; die mit 2 inkrementierte Adresse in ax in pArr speichern
    
           mov dl,[pArr] ; den Inhalt des Speichers, dessen Adresse sich in pArr befindet, in dl speichern
    
           mov ah,02h ; den Wert 02h im register ah speichern (Wert in dl ausgeben)
           int 21h    ; den DOS - Interrupt 21h aufrufen
           mov ah,4ch ; den Wert 4ch im register ah speichern (programm beenden)
           int 21h    ; den DOS - Interrupt 21h aufrufen
    END START
    END
    

    Ich hoffe, jemand nimmt sich die Zeit und sieht sich das Ganze mal an! 🙂

    Mit freundlichen Grüssen Ishildur



  • mov dl,[pArr] ; den Inhalt des Speichers, dessen Adresse sich in pArr befindet, in dl speichern
    

    Hier liegt eigentlich der einzige fuer mich erstmal offensichtliche Fehler:
    Was hier passiert ist, dass du den Inhalt des Speichers bei pArr (also einen Teil des Pointers) nach dl holst.
    Was du wohl haben wolltest (indirekte Adressierung via Pointer) laesst sich nur ueber Register erreichen. zB.:

    mov si, [pArr]  ; Adresse, die in pArr steht nach si laden
    mov dl, [si]    ; den Inhalt des Speichers, dessen Adresse sich in si (und in pArr) befindet, in dl speichern
    

    Register-indirekte Adressierung funktioniert bei 16Bit in der Form nur mit den Registers bx, si, di und bp

    Was deine inkonsequente Verwendung eckiger Klammern betrifft, denke ich, dass dabei letztendlich auch das gewuenschte Ergebnis herauskommt.



  • Hey Nobuo T
    Dein Vorschlag hat super geklappt, Danke vielmals!
    Das mit den inkonsequenten Klammern war Absicht. Ich dachte mir, wenn es falsch sein sollte, wird es mit Sicherheit jemand erwähnen! 😉

    Also ich gehe davon aus, dass

    mov [Arr+2],"m"
    

    und

    mov Arr+2,"m"
    

    absolut dasselbe bewirkt?

    Ich habe noch eine Frage:
    Leider lässt sich folgende Anweisung nicht assemblieren, warum nicht, dass muss doch gehen?

    mov es:[si],[bp+4]
    

    Habs nun so gelöst, aber ist so üblich?

    mov bx,[bp+4]
    mov es:[si],bx
    

    Noch eine letzte Frage:
    Wenn ich einer Prozedur Parameter übergeben will, so muss ich diese ja pushen:

    push 0fh
    push 34h
    call DoSomething
    

    Nur leider klappt das auch wieder nicht, ich musste es nun so machen:

    mov ax,0fh
    push ax
    mov ax,34h
    push ax
    call DoSomething
    

    Muss dass wirklich so sein? 🙄

    Einen freundlichen Gruss besonders an Nobuo T
    Ich bin dir sehr Dankbar für deine Hilfestellungen!



  • Ishildur schrieb:

    Das mit den inkonsequenten Klammern war Absicht. Ich dachte mir, wenn es falsch sein sollte, wird es mit Sicherheit jemand erwähnen! 😉

    Also ich gehe davon aus, dass

    mov [Arr+2],"m"
    

    und

    mov Arr+2,"m"
    

    absolut dasselbe bewirkt?

    Naja, nicht wirklich. Kommt auf den verwendeten Assembler an. idR. kann man bei Intel-Syntax aber allgemein sagen, dass eckige Klammern einen Speicherzugriff darstellen. Insofern waerst du mit 1. Variante eher auf der sicheren Seite.

    Ishildur schrieb:

    Ich habe noch eine Frage:
    Leider lässt sich folgende Anweisung nicht assemblieren, warum nicht, dass muss doch gehen?

    mov es:[si],[bp+4]
    

    Nein, geht nicht. Ich kenne auch nicht viele verbreitete CPU, die so etwas koennen.

    Ishildur schrieb:

    Habs nun so gelöst, aber ist so üblich?

    mov bx,[bp+4]
    mov es:[si],bx
    

    Jup. Entweder so ueber ein Register, oder "direkt" mit der String-Operationen movs. zB. movsd kopiert ein dword direkt von ds:(e)si nach es:(e)di (weitere String-Operationen waeren cmps, scas, lods und stos - google o.Ae. fuer weitere Infos).
    Da hierfuer aber zuerst mal das si und di geladen werden muessen, macht das wirklich nur fuer umfangreichere Kopieraktionen Sinn.

    Ishildur schrieb:

    Noch eine letzte Frage:
    Wenn ich einer Prozedur Parameter übergeben will, so muss ich diese ja pushen:

    push 0fh
    push 34h
    call DoSomething
    

    Nur leider klappt das auch wieder nicht, ich musste es nun so machen:

    mov ax,0fh
    push ax
    mov ax,34h
    push ax
    call DoSomething
    

    Muss dass wirklich so sein? 🙄

    Noe... Solange du nicht mit irgendeiner Hochsprachenfunktion o.Ae. interagierst, die eine bestimmte Art der Parameteruebergabe erwartet, kannst du die uebergeben, wie du lustig bist. Da bieten sich zB. einfach bestimmte Register oft viel eher an.
    Ansonsten lassen sich Konstanten eigentlich seit dem 286 pushen. Keine Ahnung, was genau bei deinem 1. Code nicht klappt, aber ich sehe da nur 2 Moeglichkeiten:
    Entweder generierst du nur Code fuer den 8086, oder, was wahrscheinlicher ist, der Assembler weis so nicht, wie gross deine Konstanten tatsaechlich sein sollen, die du da pushen willst (steht schliesslich nicht da - so hat er theoretisch 8, 16 oder 32Bit zur Auswahl).
    Wie genau du deinem Assembler letzteres mitteilen kannst, haengt vom verwendeten Assembler ab.

    Ishildur schrieb:

    Einen freundlichen Gruss besonders an Nobuo T
    Ich bin dir sehr Dankbar für deine Hilfestellungen!

    NP. Ich bin froh, wenn ich noch jemandem mit meinem Wissen ueber museumsreife Hardware/Standards und ein bissel Assembler-Basis weiterhelfen kann. :p



  • Hallo Nobuo T
    Und wieder einmal habe ich ein merkwürdiges Phänomen zu beklagen:
    Ich habe ein Problem mit dem CallByReference, könntest du dir das mal ansehen, stehe echt auf der Leitung! 😞

    habe dazu schnell ein kleines Beispielprogramm geschrieben:

    .MODEL TINY
    
    .STACK 256
    
    SCR_W EQU 140h
    SCR_H EQU 0c8h
    
    .CODE
    Pnt DW 2 DUP(03h,07h) ; Point (xPos,yPos) je 16-Bit
    
    START: mov  ax,13h        ; Bildmodus wechseln (320x200x256)
           int  10h           ; ausführen (video)
           mov  bx,OFFSET Pnt ; statische Startadresse von Pnt in bx speichern
           mov  cl,02h        ; farbe zuordnen (Grün)
           call DrawPointFast ; DrawPointFast aufrufen
           mov  ah,08h        ; Auf Eingabe warten
           int  21h           ; ausführen (MS-DOS)
           mov  ax,03h        ; Bildschirmmodus zurücksetzen (Textmodus)
           int  10h           ; ausführen (video)
           mov  ah,4ch        ; Programm beenden
           int  21h           ; ausführen (MS-DOS)
    DrawPointFast PROC NEAR   
           mov  ax,[bx+2]     ; Die Adresse, welche im bx Register gespeichert ist um 2 inkrementieren und schliesslich den Wert an jener Adresse nach ax kopieren. => In ax sollte doch nun 0007h stehen, allerdings steht da 00ffh drinn! Wieso?
           mov  dx,SCR_W      ; Anzahl Pixel in der x - Achse nach dx kopieren
           mul  dx            ; yPos * Bildschirmbreite (Pixel)
           add  ax,[bx]       ; resultat + xPos
           mov  si,ax         ; Position in indexregister si speichern für Zeigeroperation
           mov  ax,0a000h     ; Basisadresse von UMA in ax kopieren
           mov  es,ax         ; ax nach es kopieren
           mov  es:[si],cl    ; Pixelfarbe setzen
           ret                ; zurückkehren
    DrawPointFast ENDP
    END START
    END
    

    Ich hoffe du kannst mir helfen! Bin echt aufgeschmissen!
    Lg Ishildur



  • Ich habe den Fehler endlich gefunden, nachdem ich nun ein weiteres Buch über Assemblerprogrammierung durchgelesen habe.

    Da das Datenmodell Tiny ist muss ich noch folgendes machen:

    Ich muss das Datensegment register manuell mit der Adresse des Codesegments initialisieren.

    mov ax,cs
    mov ds,ax


Anmelden zum Antworten