DOS ma dwa rodzaje plików wykonywalnych: .com
i .exe
.
Do tworzenia pierwszego wystarczy nam sam NASM, do drugiego potrzeba dodatkowo linkera.
-= program typu .com =-
COM jest łatwiejszy do napisania, ale nadaje się tylko do małych programów: których kod i dane mieszczą się w 64 kilobajtach (trochę mniej).
Cały program zajmuje jeden segment. Rejestry ds
i es
są automatycznie zainicjalizowane, więc nie trzeba się nimi przejmować.
Kod assemblerowy programu COM wygląda tak (składnia NASM):
[bits 16]
org 100h
; push cs
; pop ds
mov dx,napis
mov ah,9
int 21h
mov ax,4C00h
int 21h
napis db 'Ala ma kota',13,10,36
Linijka org 100h
jest wymagana na początku każdego programu typu COM. Później mamy (niepotrzebne tak naprawdę) instrukcje push cs
/pop ds
, które działają tak jak mov ds,cs
, choć taka dokładnie instrukcja nam się nie skompiluje. Ponieważ dane są w tym samym segmencie co kod, rejestr ds
siłą rzeczy powinien mieć tę samą wartość co cs
. Umieściłem te linie jednak w komentarzu, ponieważ mamy gwarancję że cs=ds=es
na starcie programu.
W programie typu COM mamy też zapewniony stos, więc nie trzeba się nim przejmować.
Zamiast standardowego zakończenia programu mov ax,4C00h
/int 21h
można użyć formy skróconej: ret
.
[bits 16]
org 100h
mov dx,napis
mov ah,9
int 21h
ret
napis db 'Ala ma kota',13,10,36
Na końcu napis
u napisałem: 13,10,36
. Pierwsze dwa bajty, w tej kolejności, to znak entera (przejścia do nowej linii), a 36 to kod ASCII znaku $. Mogłem napisać 13,10,'$'
, ale przyzwyczaiłem się do pisania 36
.
c:\pp\myprogs\asm>nasm kom.asm -fbin -o kom.com
c:\pp\myprogs\asm>kom
Ala ma kota
-= program typu .exe =-
EXE to większy program, ma mniej ograniczeń. Można mieć wiele segmentów kodu i wiele segmentów danych. Standardowo mamy dostęp do 640 kB pamięci, ale istnieją tzw. DOS-extendery, które pozwalają na pisanie programów w trybie chronionym, także 32-bitowych, z dostępem nawet do całego RAM-u komputera i z obsluga swapa (zależnie od możliwości ograniczeń danego extendera).
Skupię się jednak na 16-bitowym programie w tybie rzeczywistym (real).
[bits 16]
segment code
..start:
mov ax,data
mov ds,ax
mov dx,napis
mov ah,9
int 21h
mov ax,4C00h
int 21h
segment data
napis db 'Ala ma kota',13,10,36
segment stack class=stack
resb 4096
@Adam Boduch: dlaczego ten kod się nie chce pokolorować?
Program jest podzielony na trzy segmenty: kodu, danych i stosu. Nazwy segmentów są nieistotne, przyjęło się pisać: code, data, stack.
Ponieważ może być wiele segmentów kodu, system musi wiedzieć w którym miejscu zacząć wykonywanie kodu. W NASMie oznaczamy to etykietą ..start
.
Segment stosu musi mieć class=stack
, jeśli piszemy w NASMie. Poza zarezerwowaniem miejsca (tutaj 4 kB, choć starczyłoby znacznie mniej) nie trzeba nic z nim kombinować, rejestry ss
i sp
będą zainicjalizowane automatycznie.
Jednak nie będą zainicjalizowane automatycznie segmenty danych ds
i es
, a przynajmniej niekoniecznie na ten segment co trzeba. Dlatego tutaj napisałem mov ax,data
/mov ds,ax
(ponieważ nie da się zrobić bezpośrednio mov ds,data
).
Może się okazać, że w tak małym programie bez inicjalizacji ds
program będzie działał prawidłowo. Jednak nie przyzwyczajajmy się do tego – w programie typu EXE trzeba pamiętać o inicjalizacji ds
.
Nie można również zastąpić wyjścia z programu instrukcją ret
.
Taki plik .asm
kompilujemy NASMem do formatu .obj
. Plik .obj
(albo wiele plików .obj
) przekształcamy do .exe
za pomocą linkera. Tego NASM nie potrafi, trzeba mieć osobny program. Ja posłużyłem się wlink
, wchodzącym w skład pakietu Open Watcom, bo akurat go miałem na dysku:
c:\pp\myprogs\asm>nasm egze.asm -fobj
c:\pp\myprogs\asm>wlink file egze.obj
Open Watcom Linker Version 1.8
Portions Copyright (c) 1985-2002 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
loading object files
creating a DOS executable
c:\pp\myprogs\asm>egze
Ala ma kota