Mimo postępującej ekspansji Windows i języków wysokiego poziomu assembler trzyma się całkiem dobrze. Używany jest min. przez scenowców, których zaskarbił sobie szybkością i niewielką wielkością produkowanego programu. Użycie assemblera daje niezwykłą kontrolę nad komputerem. Jedyneym językiem wysokiego poziomu oferującym podobne możliwości jest C. Jak wszystko assembler nie jest pozbawiony wad, do których należą głównie praktycznie zerowa przenośność kodu i pozorne skomplikowanie. Przy pierwszym kontakcie assembler zdaje się odrzucać. W rzeczywistości jednak jest bardzo prosty. Wystarczy poznać podstawowe polecenia i można zacząć optymalizować swój kod za pomocą bezpośrednich wstawek.
Większość kursów i ksiązek o assemblerze rozpoczyna się omówieniem mikroprocesorów, organizacji pamięci, rejestrów itp. Ze względu na dużą objętość i "nudnawość" tej części postanowiłem opuścić ją. Potrzebne inforamcje będą pojawiać się w trakcie nauki.
Co będzie nam potrzebne? Po pierwsze edytor. Z góry odradzam stosowanie windozowych wynalazków w rodzaju Word. Najlepsze są edytory DOS-owe, np. ncedit, edit, czy też edytor z DOS navigator. Po drugie assembler - polecam Turbo Assembler lub Microsoft Macro Assembler lub jeden z wielu shareware'owych i freeware'owych produktów, które wcale nie ustępują konkurencji. Nie obędzię się też bez linkera, tj. programu łączącego poszczególne moduły w jedną całość. Polecam tlink. Przydatne będą też wszelakie dokumenacje sprzętu, opisy przerwań, mapy pamięci, i oczywiście odrobina dobrych chęci. Przydatne, ale nie konieczne, byłoby też jakieś doświadczenie w programowaniu.
Do rzeczy.
Na instrukcję assemblera może składać się do czterech pól :
Etykieta: Instrukcja Argument ;Komentarz
Pola etykiety, komentarza są zawsze są opcjonalne i nie muszą występować. Natomieast pole argumentu zależy od zawartości pola instrukcji. Przykład :
Start: mov ah, 10h ;załadowanie wartości do rejestru
Pole etykiety nadaje nazwę instrukcji assemblera i pozwala na np. wykonywanie skoków.
Pole instrukcji, jak sama nazwa mówi zawiera nazwę, a raczej skrót nazwy instrukcji.
W polu argumentów, jeżeli wymaga tego instrukcja, podajemy przetwarzane dane. Na przykład w naszej instrukcji :
mov ah, 10h
nakazujemy procesorowi przeniesienie wartości 10h do rejsestru ah.
Pole komentarza, które nie jest tłumaczone na kod maszynowy, zaczynamy średnikiem. Jego funkcja jest taka sama jak {} w Pascalu czy // w C/C++
Dyrektywy
Dyrektywy nie są instrukcjami dla procesora. Wykorzystuje je kompilator. Najczęsciej używane są dyrektywy danych i trybu.
Dyrektywy danych Dyurektywa EQU
Krótko mówiąc EQU definiuje stałą. Przykład :
h EQU 10 ;definiecja stałej
Wysokosc EQU h ;inna nazwa
Akumulator EQU ax ;nadanie innej nazwy rejestrowi
Dyrektywa =
Dyrektywa = jest bardzo podobna w działaniu do EQU, ale nie blokuje możliwości zmiany wartości. Przykład :
Wysokosc = 10
Wysokosc = 11
Wysokosc = Wysokosc + 1
Dyrektywy DB, DW, DD
Dyrektyw tych używa się do zaalokowania pamięci dla zmiennych. DB przydziela 1 bajt, DW 1 słowo (2 bajty), a DD podwójne słowo Przykłady :
Wysokosc DB 10
Predkosc DW 10000
Czas DD 1000000000
Można również definiować tablice :
Tbl_Wysokosci DB 1, 2, 3, 4, 5
Predkość DW 10000, 15000
Czas DD 1000000000, 20000000
Gdyby kiedyś zaszła potrzeba zadeklarowania np. takiej tablicy
Tablica DB 1,1,1,1,1 (i tak jeszcze sto razy)
mógłbyś zapisać to w krótszej postaci :
Tablica 100 dup(1)
Możesz również tylko zaalokować pamięć, bez przypisywania wartości :
Zmienna DD ?
|
Dyrektywy segmentu i prcedury
SEGMENT i ENDS dzielą kod programu na segmenty. SEGMENT może mieć cztery argumenty : typ, sposób połączenia, klasę i długość słowa. Typ określa adres rozpoczynający segment. Dla dowolnego jest to BYTE, parzystego WORD, podzielnego przez 16 PARA, lub 256 PAGE. Segmenty mogą być łączone, niełączone lub przykrywać się. Odpowiada za to typ segmentu - odpowiednio PUBLIC, PRIVATE lub COMMON. Segmnet stosu określa sie za pomocą słówka STACK. Klasa określa kolejność przechowywania. Segmenty o tej samej klasie są przechowywane "obok siebie", a o różnej tak jak zostaną napotkane. Słowo może być 16 (USE16) lub 32 (USE32) bitowe. Po dokladniejsze instrukcje odsyłam np. do pomocy Turbo Assemblera.
Dyrektywy SEGMENT i ENDS definiują tylko początek i koniec, a nie rodzaj segmentu. Zajmuje się tym dyrektywa ASSUME, której składnia jest następująca :
ASSUME rejestr segmentowy:nazwa segmentu
Uwaga ! Dyrektywa ASSUME nie zajmuje się ładowaniem segmentu danych do rejestru DS, należy samemu to zrobic.
Dyrektywy PROC i ENDP definiują początek i koniec procedury. Każda procedura zaczyna się PROC, a kończy ENDP. Powinna też zawierać (ale nie musi!) też instrukcję RET, która powoduje powrót do miejsca skąd procedura została wywołana. Dyrektywa PROC może mieć atrybut zasięgu : NEAR(wywolywana tylko ze swojego segmentu) lub FAR(wywołwana również z innych segmentów). A teraz przykład podsumowujący wszystko czego dzisiaj się nauczyliścmy.
Dyrektywa END mówi assemblerowi, że tutaj kończy się program i gdzie znajduje się punkt wejścia, inaczej gdzie DOS ma zacząć wykonawać program.
kods SEGMENT PARA PUBLIC 'CODE' ;poczatek segmentu kodu
assume cs:kods, ss:stoss, ds:danes
Czekaj PROC NEAR
Sprawdz :
mov ax, 0 ;funkcja odczytu bufora klawiatury
int 16h ;wywolanie przerwania
cmp ah, 0 ;sprawdzenie czy jest znak
je Sprawdz ;nie - skok do etykiety Sprawdz
ret ;powrot z procedury
Czekaj ENDP
Pocz :
mov ax, danes ; zaladowanie segmentu segmentu danych
mov ds, ax
mov dx, offset tekst ;ustawienie offsetu tekstu
mov ah, 9 ;funkcja wypisujaca tekst
int 21h ;wywolanie prerwania 21h
call Czekaj
Wyjscie :
mov ah, 4ch
mov al, 0h
int 21h ;powrot do systemu operacyjengo
kods ENDS ;koniec segmentu kodu
danes SEGMENT PARA PUBLIC 'DATA' ;poczatek segmentu danych
tekst db 'Hello world', 13, 10, '$' ;deklaracja zmiennej
;tekst bedacy tablica bajtow
danes ENDS ;koniec segmentu danych
stoss SEGMENT PARA STACK 'STACK' ;poczatek segmentu stosu
db 500 dup(?) ;deklaracja rozmiaru stosu
stoss ENDS ;koniec segmentu stosu
end Pocz ;koniec programu
Michał Meller
mellerm@wirtual.pl
|