Już w średnio zaawansowanych programach pojawia się potrzeba dynamicznego rezerwowania pamięci. Na przykład, użytkownik podaje nam rozmiar tablicy a my musimy taką tablicę utworzyć i na niej operować (nie znając wcześniej nawet maksymalnego jej rozmiaru). Rozwiązaniem takich problemów jest właśnie dynamiczna alokacja pamięci.
Pod DOSem pamięć alokuje się funkcją AH=48h przerwania 21h, w BX podając liczbę paragrafów do zaalokowania (1 paragraf = 16 bajtów). Jeśli alokacja pamięci się powiedzie, w AX otrzymujemy numer segmentu z zarezerwowaną dla nas pamięcią. Programy typu .com z założenia zajmują całą dostępną pamięć, więc aby coś zaalokować, należy najpierw trochę pamięci zwolnić.
Zwalnianie pamięci wykonuje się funkcją 49h, w ES podając numer segmentu do zwolnienia.
Jak widać, teoria nie jest skomplikowana. Przejdźmy więc może do przykładu. Ten krótki programik ma za zadanie zaalokować 160 bajtów, wyzerować je i na końcu zwolnić.
; Dynamiczna alokacja pamięci pod DOSem ; ; Autor: Bogdan D., bogdandr (at) op.pl ; ; kompilacja: ; ; nasm -f obj -o allocdos.obj allocdos.asm ; val allocdos.obj,allocdos.exe,,, section .text ..start: mov ah, 49h mov es, [ds:2ch] ; ES=segment naszych zmiennych środowiskowych int 21h ; zwalniamy mov ax, seg info mov ds, ax ; DS = nasz segment danych (w razie czego) mov ah, 48h ; rezerwuj pamięć mov bx, 10 ; 10 paragrafów int 21h jc problem ; CF=1 oznacza błąd mov es, ax ; ES = przydzielony segment mov ah, 9 mov dx, info int 21h ; wyświetl pierwszy napis mov cx, 160 ; tyle bajtów wyzerujemy xor di, di ; poczynając od adresu 0 w nowym segmencie xor al, al ; AL = 0 cld ; kierunek: do przodu rep stosb ; zerujemy obszar mov ah, 49h int 21h ; zwalniamy pamięć jc problem mov ah, 9 mov dx, info2 int 21h problem: mov ax, 4c00h int 21h koniec: section .data info db "Udana alokacja pamieci.",10,13,"$" info2 db "Udane zwolnienie pamieci.",10,13,"$" ; program typu .exe musi mieć zadeklarowany stos section stack stack resb 400h
Zwalnianie pamięci w programach typu .com
polega na zmianie rozmiaru segmentu kodu.
Wykonuje się to funkcją AH=4Ah przerwania 21h, w ES podając segment, którego rozmiar
chcemy zmienić (nasz segment kodu - CS), a w BX - nowy rozmiar w paragrafach.
Typowy kod wygląda więc tak:
mov ax, cs mov es, ax ; będziemy zmieniać rozmiar segmentu kodu mov bx, koniec ; BX = rozmiar segmentu kodu shr bx, 4 ; BX /= 16 - rozmiar w paragrafach inc bx ; +1, żeby nie obciąć naszego programu mov ah, 4ah ; funkcja zmiany rozmiaru int 21h
UWAGA: Etykieta koniec
musi być ostatnim elementem w kodzie programu.
Jeśli potrzeba więcej pamięci, niż DOS może nam zaoferować, można wykorzystać pamięć EMS lub XMS, o czym piszę w moim mini-kursie o korzystaniu z EMS i XMS.