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

1 comment -

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:

Valoare

Denumire

Descriere

0 stdin Intrare standard
1 stdout Iesire standard
2 stderr Iesire standard pentru mesaje de eroare
3 stdaux Dispozitiv auxiliar
4 stdprn Imprimanta standard

Principalele functii DOS pentru lucrul cu fisiere sunt:

Cod functie (se pune in AH)

Operatie

3Ch Creare fisier
3Dh Deschidere fisier
3Eh Inchidere fisier
3Fh Citire din fisier
40h Scriere in fisier
41h Stergere in fisier
42h Pozitionare in fisier
56h Redenumire 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

Parametrii intrare:

Registru corespondent

- cod functie

3Ch → AH

- nume fisier

DX

- atribut fisier

CX

Parametrii returnati:

- handler

AX

- rezultat operatie

in functie de carry flag

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

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        <strong>;incarc codul functiei</strong>
 
mov BX,handler    <strong>;incarc handler-ul fisierului existent</strong>
 
mov CX, NrOctetideScris    <strong>;indic numarul de octeti de citit din fisier
</strong>
 
lea DX,buffer        <strong>;incarca in DX adresa zonei unde pun datele citite</strong>
 
INT 21h        <strong>;apelez intreruperea 21h</strong>
 
jc eroare        <strong>;daca operatia nu a avut loc cu succes CF este setat</strong>
 
<strong>;verific reusita operatiei
</strong>
 
mov NrOctetiCititi,AX    <strong>;retin numarul de octeti efectiv cititi</strong>
 
mov rez,0        <strong>;initializez variabila rez cu 0</strong>
 
jmp final        <strong>;salt la sfarsit macro</strong>
 
eroare:                <strong>;in caz de eroare</strong>
 
mov rez,AX        <strong>;retin in rez codul erorii (este diferit de 0)</strong>
 
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]
<p style="margin-left: 108pt;">; expresie similara este si</p>
<p style="margin-left: 108pt;">; mov DX,WORD PTR pozitie</p>
<p style="margin-left: 108pt;">; mov CX,WORD PTR pozitie +2</p>
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!','$';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

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:

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.

,


  1. #1 by Attila on January 30th, 2011

    Foarte util articolul,multumesc

(will not be published)

  1. No trackbacks yet.