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