8086 Assembler: INT 21h (DOS-Interrupt) |
Zurück zur Assemblerauswahlseite |
|
Die nachfolgende Zusammenfassung betrifft den sogenannten DOS-Interrupt INT 21h. Die Beschreibung betrifft die Verhältnisse bis MS-DOS Version 6. Ich hatte mir diese Zusammenstellung gemacht, als ich mich seinerzeit mit dem 8086-Assembler beschäftigt hatte. Aufruf und Fehlercodes bei den READ-Und Write-Funktionen Aufruf und Fehlercodes bei den READ-Und Write-FunktionenDer Aufruf läuft nach folgendem Schema ab:Man versorgt die Register mit den benötigten Eingabeparametern. Die Funktionsnummer kommt nach AH, die eventuell benötigte Unterfunktionsnummer nach AL. Die Funktion wird ausgeführt. Bis auf wenige Ausnahmen ändert sie nur die Register, die zur Übergabe der Ergebnisse dienen. Die CP/M-kompatiblen Funktionen verwenden AL zur Kennzeichnung von Fehlern. Die neueren Funktionen melden mit dem gesetzten Carryflag (CF), dass ein Fehler aufgetreten ist. Falls ja, steht im Register AX eine Fehlernummer. Fehlercodes bei den READ-und WRITE-Funktionen (READ-Funktionen: 14H, 21H, 27H und WRITE-Funktionen: 15H, 22H, 28H):
Aufbau des Attributbytes:
Directoryeinträge:
Das 1.Byte des Dateinamens hat folgende Sonderbedeutung: DTA / FCBDie CP/M kompatiblen Diskfunktionen verwenden File Control Blocks (FCB)s.Da der FCB keine Möglichkeit der Pfadangabe hat, beziehen sich diese Funktionen immer auf das aktuelle Directory. Als Wildcard-Angabe für die CP/M-kompatiblen Funktionen ist nur das ? möglich, nicht das *. Sämtlicher Datentranfers findet bei den FCB-behafteten Funktionen über die Disk Transfer Address (DTA) statt. Die DTA ist die Anfangsadresse eines beliebigen Puffers im Hauptspeicher. Die maximale Größe ist 64 K Byte. Effektiv genutzt werden kann nur der Bereich zwischen dem Offset der DTA und 0FFFFH. Hatte z.B. die DTA die Adresse 3000:FFF0H so könnten maximal 16 Bytes genutzt werden. Als Default-DTA-Adresse gibt MSDOS DS:80H vor. Da die Programme bei DS:100H beginnen, ist der Puffer somit 128 Bytes lang. Die DTA-Adresse befindet sich im Program-Segment Prefix (PSP), welches den Anfang eines jeden Programmes bildet. Im PSP befinden sich an den Offsets 5CH und 6CH ebenfalls zwei ungeöffnete FCBs. Vor Verwendung bitte die hier gemachten Angaben zum FCB prüfen, ggf. korrigieren!
normaler FCB:
drive db ? ;gewähltes Laufwerk, 0= aktuelles, 1=A, usw.
fname db 8 dup (' ') ;Dateiname, linksbündig mit Space aufgefüllt
fext db 3 dup (' ') ;Erweiterung, linksbündig mit
;Space aufgefüllt
curblk dw 0 ;Nr. des aktuellen Blockes
recln dw 0 ;logische Satzlänge (default: 80H)
fsize dd 0 ;Dateilänge in Bytes
fdate db 0,0 ;Dateidatum gepackt, jjjj jjjj mmmt tttt
ftime db 0,0 ;Dateizeit gepackt, hhhh hmmm mmms ssss
reserv db 8 dup (0) ;intern von DOS benutzt
currec db 0 ;aktueller Satz in curblk
relrec dd 0 ;relative Satznr. bei Randomverarbeitung
;keine Vorbelegung durch OPEN,
;benutzt werden:
;4 Byte bei reclen <64 bytes
;3 byte bei reclen >=64 Bytes
erweiterter FCB:
dieser Kopf wird beim erweiterten FCB vor dem normalen FCB platziert:
flag db 0ffh ;Muss-Kennzeichner für
;erweiterten FCB
dummy db 5 dup (' ') ;reserviert für zukünftige
;Benutzung
fattr db ? ;Attributbyte
spezieller FCB für Funktion 17 (Umbenennen von Dateien)
drive db ? ;gewähltes Laufwerk,
;0= aktuelles, 1=A, usw.
afname db 8 dup (' ') ;alter Dateiname, linksbündig
aext db 3 dup (' ') ;alte Erweiterung, linksbündig
db 5 dup (0) ;reserviert
nfname db 8 dup (' ') ;neuer Dateiname, linksbündig
next db 3 dup (' ') ;neue Erweiterung, linksbündig
db 9 dup (0) ;reserviert
Beispiel zur FCB-Behandlung:
comment #
Zweck: Rename eines Unterverzeichnisses
Aufruf: rendir Altname Neuname
Beide Dateinamen dürfen nur die reinen Dateinamen sein,
da mit einem FCB gearbeitet wird
Quelle: c't 1988, Heft 6, Seite 204 mit Modifikationen
#
.286c
dbl macro text ;;define a line
db text,cr,lf
endm
jmps macro to ;;kurzer Sprung
jmp short to
endm
prstr MACRO TEXT ;;PRINT STRING
CALL PRMSG
DB TEXT,0
ENDM
cr equ 0dh
lf equ 0ah
dos equ 21h
lparm equ 0080h ;Parameterlänge
parm equ 0081h ;Parameter
code segment
assume cs:code, ds:code, es:code
org 100h
start: mov cl,byte ptr cs:lparm
xor ch,ch
jcxz leer ;kein Parameter
cld
;Altname als 1. Parameter suchen
mov di,parm
mov al,' '
repe scasb ;führende blanks überlesen
je leer ;nur blanks !
lea si,[di-1] ;Anfang Altname nach DI
repne scasb ;nächstes Blank als Ende Altname suchen
jne leer ;Neuname fehlt
mov byte ptr[di-1],0 ;Markieren Ende Altname
repe scasb ;weitere blanks überlesen
je leer ;kein Neuname angegeben
lea dx,[di-1] ;Anfang Neuname nach DX
add di,cx ;hinter Neuname gehen
mov byte ptr[di],0 ;Markieren Ende Neuname
jmps name_to_fcb
leer: prstr 'Usage: RENDIR Altname Neuname'
jmp ret1
;Altname in FCB eintragen
name_to_fcb:
lea di,fcb.fname
call tofcb
jc fdrive ;Fehler im Namen
;Neuname in FCB eintragen
mov si,dx
lea di,fcb.nfname
call tofcb
jc fdrive ;Fehler im Namen
;Rename versuchen
mov fcb.attr,10h ;Attribut SubDir
mov ah,17h ;Rename mit FCB
lea dx,fcb
int dos
or al,al ;fehlerfrei?
jnz nicht_ok ;nein
jmp ret0
fdrive: or al,al ;Fehlermeldung ermitteln
jne fdrive1 ;und ausgeben
jmp mdrive
fdrive1: prstr 'alter oder neuer Name zu lang !'
jmp ret1
nicht_ok: call prmsg
dbl 'SubDir ist nicht im aktuellen Directory'
db 'oder den neuen Namen gibt es schon'
db 0
jmp ret1
mdrive: prstr 'Laufwerks- bzw. Pfadangabe nicht möglich !'
jmp ret1
tofcb proc near
comment #
Übernahme von Name und Erweiterung aus der Kommandozeile in den FCB
input <si>=Beginn des Dasteinamens, mit 0 beendet
<di>=Ziel für Dateiname in FCB
output cf=0 Name und Erweiterung in FCB eingetragen
cf=1 : al=0 Name enthält Laufwerks- oder Pfadangaben
al=1 Nume+Erw. zu lang (>11 Byte)
#
mov cx,8 ;max. Länge für Name
lea bx,[di+8] ;Offset für Erweiterung
toloop: lodsb
or al,al ;Ende des Namens?
je toret ;ja. fetig mit cf=0
cmp al,'.' ;Erweiterung?
jne to10
mov di,bx ;ja- ab jetzt in Erweiterung eintragen
mov cx,3
jmps toloop
to10: cmp al,':' ;Laufwerk ?
je toerror
cmp al,'\' ;Pfad?
je toerror
stosb
loop toloop
lodsb
or al,al ;Ende mit 0?
jz toret ;ja, dann OK
mov al,1 ;Name oder Erweiterung zu lang
jmps tofehler
toerror:
mov al,0
tofehler:
stc
toret: ret
tofcb endp
;---------------
sfcb struc ;Struktur erweiterter FCB
db 0ffh ;Flag für erweitereten FCB
db 5 dup (0)
attr db ?
drive db 0
fname db ' ' ;alter Name
fext db ' ' ;alte Erweiterung
db 5 dup (0)
nfname db ' ' ;neuer Name
nfext db ' ' ;neue Erweiterung
db 15 dup (0)
sfcb ends
fcb sfcb ><
;---------------------
;Unterprogrammsammlung
;---------------------
;PRINT MESSAGE FOLLOWING CALL PRMSG AND ENDING WITH 0
PRMSG: mov word ptr PRMSG2,di
POP di
CALL PSTR
PUSH di ;Returnadr.
mov di,0 ;mod
PRMSG2 EQU $-2
RET
;PRINT MESSAGE ADRESSED BY di, ENDING WITH 0
PSTR: mov dl,[di]
INC di
cmp dl,0
jz pstr99 ;FALLS FERTIG
mov ah,02
int 21h
jmp short PSTR
pstr99: ret
;---------------
;diverse Programmbeendigungen
ret0: mov al,0
jmps raus
ret1: mov al,1
;Programmende
raus: prstr >cr,lf<
mov ah,4ch
int dos
code ends
end start
HandlesUm eine Dateinummer zu erhalten, muss die Datei mit einer UNIX-kompatiblen Funktion (3CH, 3DH, 5AH, 5BH) eröffnet bzw. eingerichtet werden. Hierzu übergibt man den Funktionen den Dateipfad. MSDOS liefert als Ergebnis den HANDLE (=Dateinummer) zurück. Alle weiteren Zugriffe zu dieser Datei, bis hin zum Schließen, werden durch die Angabe des Handles gesteuert.5 Handles sind vordefiniert: Handle Bezeichnung Gerät --------------------------------------------- 0 STDIN Standard_Input Tastatur 1 STDOUT Standard_Output Bildschirm 2 STDERR Standard_Error Bildschirm 3 STDAUX Standard_Auxiliary RS-232 4 STDPRN Standard_Printer Drucker Beispielmacros zur Handle-Dateibehandlung:Zur Anwendung vergleiche das
dos equ 21h
;ldreg is an "inner" macro.
;It allows the caller of a macro to specify a register
;or a literal value as the parameter to the macro.
;This macro loads the correct register specified
;by the caller of the macro with the contents of
;the register, literal or ;memory location also specified.
;No code will be generated if the two ;parameters are
;the same.
ldreg macro destreg,source
ifdif <destreg>,<source>
mov destreg,source
endif
endm
;---------------------------
;handle-dateibehandlung
;---------------------------
fopen macro fname,acode ;;open file
ifdif <dx>,<fname>
mov dx,offset fname ;;address of file name
endif
ldreg al,acode ;;access code
;;0=read,
;;1=write,
;;2=read & write
mov ah,3dh ;;funtion call open file
int dos ;;returns fhandle in ax
endm
fcrat macro fname,attrb ;;create a file (eine alte Datei
ifdif <dx>,<fname> ;;gleichen Namens wird
;;dabei gelöscht). Die erzeugte Datei
;;ist geoeffnet fuer Lesen und Schreiben.
mov dx,offset fname ;;address of file name
endif
ldreg cx,attrb ;;attribute
mov ah,3ch ;;funtion call create file
int dos ;;returns fhandle in ax
endm
fwrit macro fhand,wbuff,count ;;write to file
ldreg bx,fhand ;;address of file name
ldreg cx,count ;;attribute
ifdif <dx>,<wbuff>
mov dx,offset wbuff ;;address of write buffer
endif
mov ah,40h ;;funtion write file
int dos
endm
fclose macro fhand ;;close file
ldreg bx,fhand ;;file handle
mov ah,3eh ;;function call close file
int dos
endm
fread macro fhand,rbuff,count ;;read from file
ldreg bx,fhand ;;get file handle
ldreg cx,count ;;get this many byte(s)
ifdif <dx>,<rbuff>
mov dx,offset rbuff ;;address of read buffer
endif
mov ah,3fh ;;function read handle
int dos
endm
PSP / ENVIRONDer PSP ist 256 Bytes lang und beginnt stets vor dem Programm.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||