Tutorial Limbaj de Asamblare (Assembler) Intel 8086 – Partea 6 – Lucru cu fisiere

In acest tutorial destinat imbajului de asamblare pentru procesoare din familia Intel 8086 sunt prezentate modalitatile de lucru cu fisiere:

  • Creare fisier
  • Inchidere fisier
  • Deschidere fisier
  • Scriere in fisier
  • Citire din fisier
  • Pozitionare in fisier
  • Extindere jump-uri de tip short


In programele realizate in limbaj de asamblare fisierul este identificat prin:

  • nume (sir de caractere), la operatiile de deschidere si creare
  • handler (valoare pozitiva pe 16 biti ce identifica in mod unic fisierul pe disc sau alte dispozitive), la operatiile de inchidere, citire, scriere, pozitionare

Exista o serie de handler-e asociate unor dispozitive standard:

ValoareDenumireDescriere
0stdinIntrare standard
1stdoutIesire standard
2stderrIesire standard pentru mesaje de eroare
3stdauxDispozitiv auxiliar
4stdprnImprimanta standard
Dispozitive/Iesiri standard

Principalele functii DOS pentru lucrul cu fisiere sunt:

Cod functie (se pune in AH)

Operatie

3ChCreare fisier
3DhDeschidere fisier
3EhInchidere fisier
3FhCitire din fisier
40hScriere in fisier
41hStergere in fisier
42hPozitionare in fisier
56hRedenumire fisier

Considerand urmatoarele variabile definite in segmentul de date al unui program ce foloseste fisiere:

handler    dw     ?    ;handler la fisier

atribut        dw    ?    ;atribut creare fisier

tipDeschid    dw    ?    ;modul de deschidere a  fisierului

rez        db    ?    ;variabila verificare reusita operatie

numeFis    db    'fisier.dat',0    ;nume fisier

NrOctetideScris    dw    ?    ;numarul de octeti de scris in fisier

NrOctetiScrisi        dw    ?    ;numarul de octeti scrisi efectiv in fisier


CREARE FISIER

ParametriiRegistru corespondent
– cod functie

3Ch → AH

– nume fisier

DX

– atribut fisier

CX

Parametrii returnati:

 
– handler

AX

– rezultat operatie

in functie de carry flag

Parametrii functie creare fisier

La momentul crearii, tipul fisierul poate fi:

  • read-only (1)
  • hidden (2)
  • system (4)
  • normal (0)
Creare MACRO numeFis, atribut, handler, rez

local eroare, final

push AX

push CX

push DX

mov AH,3Ch        ;incarc codul functiei

mov CX,atribut    ;pun atributul fisierului

lea DX,numeFis    ;incarca in DX adresa sirului de caractere asociat numelui

INT 21h        ;apelez intreruperea 21h

jc eroare        ;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei

mov handler,AX    ;daca fisierul a fost creat initializez handler-ul

mov rez,0        ;initializez variabila rez cu 0

jmp final        ;salt la sfarsit macro

eroare:                ;in caz de eroare

mov handler,-1    ;initializez handler-ul cu o valoare negativa

mov rez,AX        ;retin in rez codul erorii (este diferit de 0)

final:

pop DX

pop CX

pop AX

ENDM

Inchidere Fisier

Parametrii intrare:Registru corespondent
– cod functie

3Eh → AH

– handler

BX

Parametrii returnati:

 
– rezultat operatie

in functie de carry flag

Inchidere MACRO handler, rez

local eroare, final

push AX

push BX

mov AH,3Eh    ;incarc codul functiei

mov BX,handler    ;incarc handler-ul fisierului

INT 21h

jc eroare    ;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei

mov rez,0

jmp final

eroare:

mov rez,AX    ;retin in rez codul erorii (este diferit de 0)

final:

pop BX

pop AX

ENDM

DECHIDERE FISIER

Parametrii intrare:Registru corespondent
– cod functie

3Dh → AH

– nume fisier

DX

– tip acces

AL

Parametrii returnati:

 
– handler

AX

– rezultat operatie

in functie de carry flag

Deschidere fisier

Fisierul poate deschis pentru:

  • citire (0)
  • scriere (1)
  • citire/scriere (2)
Deschidere MACRO numeFis, tipDeschid, handler, rez

local eroare, final

push AX

push DX

mov AH,3Dh        ;incarc codul functiei

mov AL, tipDeschid    ;indic tipul deschiderii fisierului

lea DX,numeFis    ;incarca in DX adresa sirului de caractere asociat numelui

INT 21h        ;apelez intreruperea 21h

jc eroare        ;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei

mov handler,AX    ;daca fisierul a fost deschis initializez handler-ul

mov rez,0        ;initializez variabila rez cu 0

jmp final        ;salt la sfarsit macro

eroare:                ;in caz de eroare

mov handler,-1    ;initializez handler-ul cu o valoare negativa

mov rez,AX        ;retin in rez codul erorii (este diferit de 0)

final:

pop DX

pop AX

ENDM

Scriere in fisier

Parametrii intrare:Registru corespondent
– cod functie

40h → AH

– handler fisier

BX

– buffer din care se citesc datele pentru a fi scrise in fisier

DX

– numar octeti de scris in fisier

CX

Parametrii returnati: 
– numar octeti scrisi efectiv in fisier

AX

– rezultat operatie

in functie de carry flag

Scrie MACRO handler, buffer, NrOctetideScris, NrOctetiScrisi,rez

local eroare, final

push AX

push BX

push CX

push DX

mov AH,40h        ;incarc codul functiei

mov BX,handler    ;incarc handler-ul fisierului existent

mov CX, NrOctetideScris    ;indic numarul de octeti de scris in fisier

lea DX,buffer        ;incarca in DX adresa zonei de unde iau datele de scris

INT 21h        ;apelez intreruperea 21h

jc eroare        ;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei

mov NrOctetiScrisi,AX    ;retin numarul de octeti efectiv scrisi

mov rez,0        ;initializez variabila rez cu 0

jmp final        ;salt la sfarsit macro

eroare:                ;in caz de eroare

mov rez,AX        ;retin in rez codul erorii (este diferit de 0)

final:

pop DX

pop CX

pop BX

pop AX

ENDM

Atentie Buffer-ul poate fi un element de tip articol, masiv sau variabila. De exemplu, pentru a scrie intr-un fisier primele 3 elemente ale unui vector vector db 1,2,3,4,5b se scrie instructiunea:

Scrie handler,vector,3,NrOctetiScrisi,rez

Citire din Fisier

Parametrii intrare:Registru corespondent
– cod functie

3Fh → AH

– handler fisier

BX

– buffer in care se scriu datele citite din fisier

DX

– numar octeti de citit din fisier

CX

Parametrii returnati: 
– numar octeti cititi efectiv din fisier

AX

– rezultat operatie

in functie de carry flag

Citeste MACRO handler, buffer, NrOctetideCitit, NrOctetiCititi,rez

local eroare, final

push AX

push BX

push CX

push DX

mov AH,3Fh        

;incarc codul functiei

mov BX,handler    

;incarc handler-ul fisierului existent

mov CX, NrOctetideScris    

;indic numarul de octeti de citit din fisier

lea DX,buffer        

;incarca in DX adresa zonei unde pun datele citite

INT 21h        

;apelez intreruperea 21h

jc eroare        

;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei

mov NrOctetiCititi,AX    

;retin numarul de octeti efectiv cititi

mov rez,0        

;initializez variabila rez cu 0

jmp final        

;salt la sfarsit macro

eroare:                

;in caz de eroare

mov rez,AX        

;retin in rez codul erorii (este diferit de 0)

final:

pop DX

pop CX

pop BX

pop AX

ENDM

Pozitionare in fisier

Parametrii intrare:

Registru corespondent

– cod functie

42h → AH

– handler fisier

BX

– punct de referinta

AL

– numar octeti fata de punctul de referinta ai saltului (e un double)

cuv. inferior → DX

cuv. superior → CX

Parametrii returnati: 
– noua pozitie in fisier (un double)

cuv. inferior → AX

cuv. superior → DX

– rezultat operatie

in functie de carry flag

Punctul de referinta poate fi:

  • 0, inceputul fisierului;
  • 1, pozitia curenta in fisier;
  • 2, sfarsitul fisierului.
Pozitionare MACRO handler, pozitie, referinta, pozitieNoua, rez

local eroare, final

push AX

push BX

push CX

push DX

mov AH,42h        ;incarc codul functiei

mov AL,referinta    ;indic referinta fata de care fac saltul

mov BX,handler    ;incarc handler-ul fisierului existent

mov DX,word ptr pozitie[0]    ;numar octeti salt

mov CX,word ptr pozitie[2]

; expresie similara este si

; mov DX,WORD PTR pozitie

; mov CX,WORD PTR pozitie +2

INT 21h

jc eroare        ;daca operatia nu a avut loc cu succes CF este setat

;verific reusita operatiei

mov word ptr pozitieNoua[0],AX    ;noua pozitie

mov word ptr pozitieNoua[2],DX

mov rez,0

jmp final        ;salt la sfarsit macro

eroare:                ;in caz de eroare

mov rez,AX        ;retin in rez codul erorii (este diferit de 0)

final:

pop DX

pop CX

pop BX

pop AX

ENDM

Presupunand ca toate aceste macrodefinitii sunt definite in fisierul MacroFis.inc se scrie programul care construieste un fisier si il foloseste pentru a memora elementele unui vector de elemente si de structuri. Ulterior, se construiesc alti doi vectori in care se pun elementele aflate in fisier.

Atentie Fisierul MacroFis.inc contine doar codul fiecarei macrodefinitii in parte fara nici o alta declaratie in plus. Acest fisier nu necesita asamblare sau link-editare. Instructiunea include
MacroFis.inc din programul principal (dat mai jos) copiaza codul din fisierul indicat si il insereaza pe pozitia instructiunii.

Atentie Pentru a determina dimensiunea unui vector se va utiliza simbolul $ asociat offset-ului curent in segmentul de date.

Pentru un masiv de tip tip_vect (orice tip de baza sau structura) pentru lungime ca numar de elemente se utilizeaza expresia:

vector tip_vector elem1, elem2, elem3, ….., elemn

tip equ TYPE vector

nrElem equ ($ – vector)/tip

In cazul masivelor definite cu dup se poate utiliza LENGTH pentru a obtine numarul de elemente.

.model small
.286
.stack 100h
.data

	student STRUC	;articol de tip student
		nume db 15 dup (?)
		varsta db ?
		nrMatricol dw ?
	ENDS
		
	dimStudent equ SIZE student	;dimensiune in octeti a unui 
;articol de tip student

	vector db 1,2,3,4,5	;vector de elemente
	lvector equ $-vector	;lungime vector ca numar de octeti
;cum elementele vectorului sunt de tip octet atunci lvector 
;da si numarul de elemente
	vector2 db 5 dup(?)	;al doilea vactor

	vectorStudenti	student <'Popescu',23,1234>,<'Ionescu',22,1235>,<'Gheorghe',22,1236>
					;vector de articole
	dimVectStud equ $-vectorStudenti	;dimensiune in octeti
	nrStudenti equ dimVectStud/dimStudent	;numar elemente
	vectorStudenti2 student nrStudenti dup(?)	;al doilea vector
	
	
	handler		dw 	?	;handler la fisier
	atribut		dw	?	;atribut creare fisier
	tipDeschid	dw	?	;modul de deschidere a  fisierului
	rez		dw	?	;variabila verificare reusita operatie
	NrOctetideScris	dw	?	;numar de octeti de scris in fisier
	NrOctetiScrisi	dw	?	;numar de octeti scrisi in fisier
	NrOctetiCititi	dw	?	;numar de octeti de cititi din 
;fisier
	Pozitie		dd	?	;dimensiunea saltului la 
;pozitionare
	PozitieNoua	dd	?		;noua pozitie in fisier
	
	numeFis	db	'fisier.dat',0	;nume fisier
	mesajEroare db	'Eroare executie functie!','

Atentie Salturile conditionate nu pot referi etichete aflate la mai mult de 128 octeti. Solutia consta in evitarea acestor situatii prin rescrierea codului si a conditiei de verificat astfel incat sa avem salturi mai mici. In exemplul anterior, verificarea realizarii corecte a unei macrodefinitii se realiza prin:

        apel de macrodefinitie
        cmp rez,0
        jne afiseaza_eroare
        apel macrodefinitie urmatoare
        …
        jmp exit
afiseaza_eroare:
	AfiseazaMesaj mesajEroare
exit:
	mov AX,4c00h
	int 21h

insa eticheta afiseaza_eroare se afla la o distanta mai mare de 128 de octeti. Din acest motiv s-au folosit etichetele continuarei cu i = 1,2.. iar verificarea a devenit:

         apel de macrodefinitie
         cmp rez,0
         je continuarei
         AfiseazaMesaj mesajEroare
continuarei
         apel macrodefinitie urmatoare

Extindere jump-uri de tip short

Se presupune secventa de cod

      efectuare comparatie
      je salt
      ...
salt:

care este corecta in cazul in care eticheta salt se gaseste la mai putin de 128 de octeti. In caz contrar saltul, extinderea salturilor conditionate se realizeaza prin abordarea secventei de cod astfel:

  • utilizarea unui salt neconditionat (acesta poate face salturi mai mari de 128 de octeti):
               efectuare comparatie
               jne continuare
               jmp salt
continuare:
               ...
salt:
  • repetarea codului de la instructiunea salt pentru fiecare comparatie:
               efectuare comparatie
               jne continuare
salt:
               ...
continuare:
               ...
  • utilizarea unui salt neconditionat fara a utiliza etichete suplimentare
      efectuare comparatie
      jne $+2+ dimensiune in octeti a instructiunii urmatoare
      jmp salt
      ...
salt:

Instructiunea jne $+2+ dimensiune in octeti a instructiunii urmatoare adauga la offset-ul curent din segmentul de cod (retinut in IP si indicat cu $) 2 octeti reprezentand dimensiunea acestei instructiunii si dimensiunea in octeti a instructiunii urmatoare. Cum in aceasta abordare instructiunea urmatoare este jmp salt trebuie indicata dimensiunea ei (vezi documentatie Structuri de control → 3 octeti pentru jump near si 5 octeti pentru jump far). Deci, in acest caz instructiunea se mai poate scrie jne $ + 5. Pentru a afla dimensiunea altor instructiuni se utilizeaza TurboDebugger-ul si se fac diferente de offset-uri ale instructiunilor respective. Pentru a fi sigur de tipul jump-ului se indica tipul acestuia explicit cu jmp NEAR PTR salt aceasta instructiune avand 3 octeti.

;mesaj eroare 
.code 
    include MacroF.inc ;includ fisierul ce contine macrodefinitiile 
start: 
    mov AX,@data 
    mov DS,AX 
    Creare numeFis,0,handler,rez ;creez fisierul 
    cmp rez,0 ;verific executia operatiei 
    je continuare1 
    AfiseazaMesaj mesajEroare ;afisez mesaj eroare 
continuare1: 
    Inchidere handler,rez ;inchid fisierul 
    cmp rez,0 ;verific executia operatiei 
    je continuare2 
    AfiseazaMesaj mesajEroare ;afisez mesaj eroare 
continuare2: 
    Deschidere numeFis,2,handler,rez ;deschid fisierul 
    cmp rez,0 ;verific executia operatiei 
    je continuare3 
    AfiseazaMesaj mesajEroare ;afisez mesaj eroare 
continuare3: 
    Scrie handler,vector,lvector,NrOctetiScrisi,rez ;scriu in fisier primul vector 
    Scrie handler,vectorStudenti,dimvectstud,NrOctetiScrisi,rez ;scriu in fisier primul vector de articole 
    mov word ptr pozitie,0 ;indic pozitia saltului 
    mov word ptr pozitie[2],0   ;pun zero pt. a ma pozitiona la 0 
                                ;octeti fata de inceputul fisierului 
    Pozitionare handler,pozitie,0,PozitieNoua,rez ;ma pozitionez pe inceputul fisierului 
    Citeste handler,vector2,lvector,NrOctetiCititi,rez  ;citesc in al doilea vector elementele din 
                                                        ;fisier: 1,2,3,4,5 
    Citeste handler,vectorStudenti2,dimVectStud,NrOctetiCititi,rez ;citesc in al doilea vector de articole 
                                                        ;elementele din fisier 
    Inchidere handler,rez ;inchid fisierul 
    mov AX,4c00h 
    int 21h 
    end start 

Codul macrodefinitiei AfiseazaMesaj este (este inclus tot in MacroF.inc) :

AfiseazaMesaj MACRO mesaj 
    push AX 
    push DX 
    mov Ah,09h 
    lea DX,mesaj 
    int 21h 
    pop DX 
    pop AX 
ENDM