asm


6. Programowanie w asemblerze

6.1 Pliki źródłowe

Każdy język programowania traktuje pliki o określonym rozszerzeniu jako swoje pliki źródłowe, to jest pliki, w których wpisany jest program, a które po przetworzeniu na drodze asemblacji lub kompilacji stają się plikami uruchamialnymi programów. W asemblerze pliki źródłowe powinny posiadać rozszerzenie *.asm. Do utworzenia pliku o takim rozszerzeniu może posłużyć dowolny edytor tekstu pozwalający na zachowanie pliku w postaci tekstowej, a więc może to być program edit.com, ncedit.exe, notepad.exe, itp. W takim pliku tekstowym należy wpisać program spełniający wszystkie wymagania co do składni, a następnie poddać go procesowi przetwarzania na wersję uruchamialną.

6.2. Narzędzia programistyczne

Język asembler jest językiem niskiego poziomu, toteż narzędzia jakie programista ma do dyspozycji są na ogół proste. Można wyróżnić trzy główne programy, jakie są niezbędne do napisania i przetworzenia programu w asemblerze. Są to:

  1. tasm.exe - (asemblacja) program ten służy do analizy programu źródłowego pod kątem poprawności ze składnią języka. Użycie tego programu jest następujące:

tasm nazwa_pliku.asm

Jeżeli program jest napisany poprawnie, pojawi się stosowny komunikat informujący nas o tym fakcie oraz powstanie plik o takiej samej nazwie, jaką posiada plik źródłowy i rozszerzeniu *.obj. W przeciwnym wypadku pojawią się komunikaty o błędach wyświetlające numer linii, w której popełniono błąd i zdawkową informację na czym ten błąd polega. Aby błąd poprawić należy edytować plik źródłowy, odszukać błędną linię, poprawić błąd i powtórzyć operację asemblacji.

  1. tlink.exe - (konsolidacja) program ten służy do utworzenia wersji uruchamialnej programu na podstawie pliku obiektowego (*.obj). Na ogół w prostych zastosowaniach wywołanie tego programu zawsze zakończy się sukcesem i utworzeniem pliku o takiej samej nazwie, jak plik obiektowy i rozszerzeniu (najczęściej) *.exe o ile proces asemblacji przebiegł bezbłędnie. Użycie tego programu jest następujące:

tlink nazwa_pliku.obj

  1. td.exe - (praca krokowa) programu tego używa się w sytuacji, gdy udało się utworzyć program uruchamialny, ale nie działa on poprawnie, tzn. jest w nim jakiś błąd nie składniowy, lecz funkcjonalny. Wówczas wykorzystujemy narzędzie td.exe do pracy krokowej, sprawdzając krok po kroku jak działa program, jakie wartości przyjmują wybrane zmienne, itp. Użycie tego programu jest następujące:

td nazwa_pliku.exe

Aby jednak plik *.exe mógł być uruchomiony z programem td.exe, należy dołączyć do niego pewne dodatkowe informacje. Aby tak się stało, należy dokonać procesu asemblacji i konsolidacji w sposób następujący:

tasm /zi nazwa_pliku.asm

tlink /v nazwa_pliku.obj

Odpowiednie opcje (/zi oraz /v) programów tasm.exe i tlink.exe pozwolą na dodanie do pliku wynikowego *.exe tych informacji, których potrzebuje program td.exe. Obsługę programu td.exe należy opanować we własnym zakresie.

6.3. Elementy składni

Każdy język programowania wymaga odpowiedniej organizacji pliku źródłowego, tj. odpowiedniego rozmieszczenia elementów języka, zachowania kolejności pewnych sekcji, użycia odpowiednich słów kluczowych, aby zawartość pliku źródłowego nie została uznana za list do ulubionej koleżanki, ale za program źródłowy danego języka. Tak jest też i w przypadku asemblera. W pliku źródłowym powinny się znaleźć następujące elementy (idąc od góry):

a) .model nazwa_modelu - określenie modelu pamięci. W prostych zastosowaniach możliwe modele pamięci to small i tiny.

b) .stack rozmiar_stasu_w_bajtach - określenie rozmiaru stosu dla programu. W prostych zastosowaniach wystarczy 512-bajtowy stos.

c) .data - ta dyrektywa rozpoczyna część programu, w której deklaruje się zmienne.

d) .code - ta dyrektywa rozpoczyna część programu, w której wpisuje się kod.

e) end - kończy program w sensie struktury.

Ad a)

Przyjęcie modelu pamięci determinuje, ile miejsca w pamięci pozostaje na program, dane i stos. Dla modelu tiny wszystkie segmenty są łączne, to znaczy, że program, stos i dane muszą się zmieścić w jednym segmencie, przy czym na program przypada 32kB pamięci, a łącznie na dane i stos także 32kB. Tak więc ten typ pamięci służy do pisania małych programów operujących na niewielkiej liczbie danych.

Ad b)

Stos powinien być w programie zadeklarowany, ponieważ nawet jeżeli programista świadomie go nie używa, to stos jest wykorzystywany podczas wywołań podprogramów lub podczas realizacji przerwań programowych. Jeżeli nie ma stosu, program konsolidujący wyświetli ostrzeżenie.

Ad c)

Trudno sobie wyobrazić program nie operujący na danych, toteż dane trzeba zadeklarować. W asemblerze generalnie można mówić o trzech typach danych:

Pierwszy z typów jest traktowany jako ciąg bitów w pamięci, które to bity mogą opisywać liczby różnych typów: liczby binarne proste, liczby binarne U2 i liczby rzeczywiste. Z tym, że to programista powinien wiedzieć, jak interpretować zawartość zmiennej (jakiego typu jest zawartość zmiennej). Deklaracje tego typu zmiennej odbywa się w następujący sposób:

nazwa_zmiennej rozmiar wartosc_pocz

przy czym w miejscu rozmiar pojawić się może:

- DB - oznaczać to będzie, że wartości zmiennej będą zapisywane w pamięci na jednym bajcie,

- DW - oznaczać to będzie, że wartości zmiennej będą zapisywane w pamięci na dwóch bajtach,

- DD - oznaczać to będzie, że wartości zmiennej będą zapisywane w pamięci na czterech bajtach.

- wartosc_pocz - początkowa wartość zmiennej (może być dowolna). Nadanie wartości jest konieczne, bowiem dopiero w chwili nadania wartości zmiennej zostaje jej przydzielona w pamięci odpowiednia liczba bajtów.

Przykład.

liczba DW 0

Drugi z typów służy tylko i wyłącznie do deklaracje ciągu znaków, które w następstwie będą wyświetlane na ekranie. Deklaracja tego typu zmiennej odbywa się w sposób następujący:

nazwa_zmiennej DB `Tu wpisz wyświetlany tekst$'

Bardzo istotne jest postawienie znaku `$' na końcu wyświetlanego tekstu, bowiem funkcja wyświetlająca znak po znaku z tego ciągu znaków zakończy ich wyświetlanie, gdy napotka znak `$'.

Przykład.

tekst db `Ala ma kota$'

Trzeci z typów (tablicowy) umożliwia deklarację w programie zmiennych, które będą zajmowały w pamięci pewną liczbę kolejnych bajtów (słów, podwójnych słów), czyli tablicę. Sposób deklaracji tego typu zmiennych jest następujący:

nazwa_zmiennej rozmiar liczba_elementów dup(`znak wypełniający tablicę')

Przykład.

tab db 100 dup(`0')

Ad d), e)

Pomiędzy dyrektywami .code i end wpisujemy program. To ta część naszego pliku źródłowego będzie skojarzona z rejestrem segmentowym CS.

6.4. Wywołania systemowe

Tak się składa, że programiści bardzo często nie piszą wszystkiego w asemblerze na piechotę, lecz korzystają z faktu, że wiele rzeczy można zrealizować wywołując pewne usługi BIOS-u lub DOS-u. Chodzi tu po prostu o zasadę, że nie wyważa się drzwi otwartych, czyli że np. jeżeli ktoś chce wyczyścić ekran, to nie zabiera się do tego w ten sposób, że bezpośrednio do pamięci ekranu zapisuje 64kB spacji tylko wywołuje odpowiednią usługę i ekran jest wyczyszczony. Pozostaje już tylko odpowiedź na pytanie jak te usługi wywoływać. W telegraficznym skrócie rzecz ma się następująco:

Podczas startu systemu tworzona jest w pamięci tzw. tablica wektorów przerwań zawierająca adresy w pamięci, gdzie znajdują się rzeczone wcześniej usługi. Tworzenie tej tablicy odbywa się dwuetapowo, tzn. część adresów usług wpisuje do niej BIOS, a reszta jest dopisywana po fakcie startu systemu operacyjnego DOS. Sięgnięcie do odpowiedniej usługi jest możliwe jedynie w przypadku wywołania przerwania. A że los zdarzył, że oprócz przerwań sprzętowych (generowanych przez urządzenia wchodzące w skład systemu komputerowego) występuje także grupa przerwań programowych (te może sobie generować dowolny, nawet średnio zaawansowany programista za pomocą instrukcji INT). W momencie wystąpienia przerwania następuje odwołanie do tablicy wektorów przerwań pod adres numer_przerwania*4, tam odnajdowane są cztery bajty adresu procedury obsługi danego przerwania, czyli upragnionej usługi. Niektóre przerwania mają wiele usług i wtedy należy dodatkowo oprócz wywołania

INT nr_przerwania

podać numer usługi w ramach tego przerwania do zrealizowania. Np. przerwanie 10h to jest zbiór procedur obsługi ekranu. Można za ich pomocą zrealizować całe mnóstwo operacji od odczytu pozycji kursora na ekranie po zdefiniowanie własnej palety kolorów. Usługi te mają swoje numery i wybór konkretnej usługi w ramach danego przerwania odbywa się poprzez podanie jej numeru. Rejestrem, który jest zawsze domyślnie sprawdzany w celu określenia numeru usługi jest rejestr AH. Chcąc zatem wywołać usługę numer 10h przerwania 10h należy to zrobić w sposób następujący:

mov ah,10h

int 10h

Czasem do wywołania określonej usługi należy podać pewne dodatkowe parametry w innych rejestrach procesora, chociażby aby ustawić pozycję kursora na ekranie trzeba w jakiejś parze rejestrów tą pozycję podać. Czasem z kolei w wyniku wykonania określonej usługi zwracane są pewne parametry do wybranych rejestrów procesora, chociażby wywołując usługę odczytującą pozycję kursora na ekranie, usługa ta do jakichś rejestrów wpisze odczytaną pozycję kursora. Zmierzam do tego, że zawsze dobrze jest dokładnie poczytać:

  1. Co przerwanie robi.

  2. Czy przerwanie ma wiele usług, bo jeżeli tak, to istotny będzie wybór usługi do realizacji.

  3. Czy do poprawnego wykonania usługi nie trzeba określić dodatkowych parametrów.

  4. Czy w wyniku wykonania usługi nie są zwracane wyniki, bo jeżeli tak, to może przed wywołaniem tej usługi konieczne będzie zachowanie zawartości rejestrów, które usługa modyfikuje wpisując wyniki swojego działania.

Wszystkie powyższe kroki należy przeprowadzić zanim wywołamy przerwanie.

Bardzo istotne jest to, że numery przerwań poniżej 21h są to przerwania BIOS-u, natomiast powyżej 21h, to usługi DOS-u. Na ogół jest tak, że usługi DOS-u są dublowane przez usługi BIOS-u i odwrotnie. Słowem jest wiele dróg do szczęścia w postaci działającego programu.

6.5. Pierwszy program

Pierwszy program w asemblerze może wyglądać następująco:

.model small

.stack 512

.code

mov ah,4ch

int 21h

end

Powyższy program należy zasemblować:

tasm nazwa_programu.asm

tlink nazwa_programu.obj

Powstały plik *.exe można uruchomić. Powyższy program ma dwie zasadnicze zalety, tj. nic nie robi oraz nie zawiesza komputera, będąc przy tym w pełni zgodnym ze składnią języka.

6.6. Makra

Przy wielokrotnym powtarzaniu się różniących się nieznacznie fragmentów programu można sobie ułatwić życie stosując makra, to jest rzeczywisty ciąg operacji jakiemu podlegają abstrakcyjne zmienne przeciążane wirtualnie w momencie wywołania poprzez wykorzystanie mechanizmów inline tj. wplatania (he! he!). Lepiej (tego jestem pewien) wyjaśni to przykład:

Program 1

;definicja stalej oznaczajacej numer koloru

BIALY EQU 15

.model small

.stack 512

.data

txt1 db 'Tekst 1',10,13,'$'

txt2 db 'Tekst 2',10,13,'$'

txt3 db 'Tekst 3',10,13,'$'

txt4 db 'Tekst 4',10,13,'$'

.code

;ustalenie segmentu danych (dobrze, żeby to było zaraz na poczatku programu)

mov ax,@data

mov ds,ax

;ustawienie aktywnej strony (usluga BIOS-u: przerwanie 10h, funkcja 05h)

mov al,0 ;numer strony

mov ah,05h

int 10h

;wyczyszczenie ekranu (usluga BIOS-u: przerwanie 10h, funkcja 06)

mov al,0

mov ch,0 ;lewy gorny wiersz okna

mov cl,0 ;lewa gorna kolumna okna

mov dh,25 ;prawy gorny wierz okna

mov dl,80 ;prawa gorna kolumna okna

mov bh,BIALY

mov ah,06h

int 10h

;ustawienie kursora na poczatku (usluga BIOS-u: przerwanie 10h, funkcja 02h)

mov dh,0 ;wiersz

mov dl,0 ;kolumna

mov bh,0 ;numer strony

mov ah,02h

int 10h

;wyswietlenie pierwszego tekstu (usluga DOS-u: przerwanie 21h, funkcja 09h)

lea dx,txt1

mov ah,09h

int 21h

;wyswietlenie drugiego tekstu (usluga DOS-u: przerwanie 21h, funkcja 09h)

lea dx,txt2

mov ah,09h

int 21h

;wyswietlenie trzeciego tekstu (usluga DOS-u: przerwanie 21h, funkcja 09h)

lea dx,txt3

mov ah,09h

int 21h

;wyswietlenie czwartego tekstu (usluga DOS-u: przerwanie 21h, funkcja 09h)

lea dx,txt4

mov ah,09h

int 21h

;czekanie na wcisniecie klawisza (usluga DOS-u: przerwanie 21h, funkcja 01h)

mov ah,01h

int 21h

;zakonczenie programu (usługa DOS-u: przerwanie 21h, funkcja 4ch)

mov ah,4ch

int 21h

end

Powyższy program zajmuje 43 linie wraz z komentarzami. Gdyby nie te właśnie komentarze, to byłby on mało nieczytelny. A teraz taki sam program, ale wykorzystujący makra...

Program 2

;definicja stalej oznaczajacej numer koloru

BIALY EQU 15

.model small

.stack 512

.data

txt1 db 'Tekst 1',10,13,'$'

txt2 db 'Tekst 2',10,13,'$'

txt3 db 'Tekst 3',10,13,'$'

txt4 db 'Tekst 4',10,13,'$'

clrscr macro

;ustawienie aktywnej strony (usluga BIOS-u: przerwanie 10h, funkcja 05h)

mov al,0 ;numer strony graficznej

mov ah,05h

int 10h

;wyczyszczenie ekranu (usluga BIOS-u: przerwanie 10h, funkcja 06)

mov al,0

mov ch,0 ;lewy gorny wiersz okna

mov cl,0 ;lewa gorna kolumna okna

mov dh,25 ;prawy gorny wierz okna

mov dl,80 ;prawa gorna kolumna okna

mov bh,BIALY

mov ah,06h

int 10h

;ustawienie kursora na poczatku (usluga BIOS-u: przerwanie 10h, funkcja 02h)

mov dh,0 ;wiersz

mov dl,0 ;kolumna

mov bh,0 ;numer strony graficznej

mov ah,02h

int 10h

endm

write macro txt

;wyswietlenie tekstu (usluga DOS-u: przerwanie 21h, funkcja 09h)

lea dx,txt

mov ah,09h

int 21h

endm

readkey macro

;czekanie na wcisniecie klawisza (usluga DOS-u: przerwanie 21h, funkcja 01h)

mov ah,01h

int 21h

endm

exit macro

;zakonczenie programu (usluga DOS-u: przerwanie 21h, funkcja 4ch)

mov ah,4ch

mov al,0 ;kod wyjscia

int 21h

endm

.code

;ustalenie segmentu danych (dobrze, żeby to było zaraz na poczatku programu)

mov ax,@data

mov ds,ax

;czyszczenie ekranu

clrscr

;wyswietlenie pierwszego tekstu

write txt1

;wyswietlenie drugiego tekstu

write txt2

;wyswietlenie trzeciego tekstu

write txt3

;wyswietlenie czwartego tekstu

write txt4

;czekanie na wcisniecie klawisza

readkey

;zakonczenie programu

exit

end

Teraz program zajmuje 16 linii, a co do czytelności to odpowiedzcie sobie sami...

Istotne jest to, że w miejscu wywołania makra wstawiane są fizycznie linie, które makro opisuje, toteż nikogo nie powinno dziwić, że program 1 i 2 w wersji uruchamialnej mają dokładnie taki sam rozmiar (w moim przypadku 632 bajtów)...

6.7. Procedury

Procedury są z kolei modułem programowym, który może, w przeciwieństwie do makr, być udostępniany na zewnątrz. Udostępniać na zewnątrz można także zmienne, ale tylko globalne. Sytuacja ta dotyczy przypadku, gdy jeden program składa się z wielu plików składowych. Program działający identycznie, jak przedstawione w rozdziale poprzednim, ale zrealizowany przy użyciu procedur może wyglądać następująco:

;definicja stalej oznaczajacej numer koloru

BIALY EQU 15

.model small

.stack 512

.data

txt1 db 'Tekst 1',10,13,'$'

txt2 db 'Tekst 2',10,13,'$'

txt3 db 'Tekst 3',10,13,'$'

txt4 db 'Tekst 4',10,13,'$'

.code

;segmentu danych (dobrze, żeby to było zaraz na poczatku programu)

mov ax,@data

mov ds,ax

;czyszczenie ekranu

call clrscr

;wyswietlenie pierwszego tekstu

lea dx,txt1

push dx ;odlozenie na stosie adresu tekstu 1

call write

;wyswietlenie drugiego tekstu

lea dx,txt2

push dx ;odlozenie na stosie adresu tekstu 2

call write

;wyswietlenie trzeciego tekstu

lea dx,txt3

push dx ;odlozenie na stosie adresu tekstu 3

call write

;wyswietlenie czwartego tekstu

lea dx,txt4

push dx ;odlozenie na stosie adrseu tekstu 4

call write

;czekanie na wcisniecie klawisza

call readkey

;zakonczenie programu

call exit

;czesc programu, do ktorej nie ma mozliwosci wejscia normalnym trybem

clrscr proc

;ustawienie aktywnej strony (usluga BIOS-u: przerwanie 10h, funkcja 05h)

mov al,0 ;numer strony

mov ah,05h

int 10h

;wyczyszczenie ekranu (usluga BIOS-u: przerwanie 10h, funkcja 06)

mov al,0

mov ch,0 ;lewy gorny wiersz okna

mov cl,0 ;lewa gorna kolumna okna

mov dh,25 ;prawy gorny wierz okna

mov dl,80 ;prawa gorna kolumna okna

mov bh,BIALY

mov ah,06h

int 10h

;ustawienie kursora na poczatku (usluga BIOS-u: przerwanie 10h, funkcja 02h)

mov dh,0 ;wiersz

mov dl,0 ;kolumna

mov bh,0 ;numer strony

mov ah,02h

int 10h

ret

endp

write proc

;wyswietlenie tekstu (usluga DOS-u: przerwanie 21h, funkcja 09h)

; sutuacja na stosie jest nastepujaca (model small, wywolanie bliskie)

; XXXXh <- na wierzcholku jest adres powrotu do pr. gl.

; XXXXh <- tu jest odlozony adres tekstu

pop di ;teraz di zawiera adres powrotu

pop dx ;teraz dx zawiera adres tekstu do wyswietlenia

mov ah,09h

int 21h

push di ;koniecznie przed "ret" odlozyc adres powrotu

;na stos, bo inaczej bedzie powrot w krzaki...

ret

endp

readkey proc

;czekanie na wcisniecie klawisza (usluga DOS-u: przerwanie 21h, funkcja 01h)

mov ah,01h

int 21h

ret

endp

exit proc

;zakonczenie programu (usluga DOS-u: przerwanie 21h, funkcja 4ch)

mov ah,4ch

mov al,0 ;kod wyjscia

int 21h

ret

endp

end

Jak widać, program główny nieco się wydłużył w stosunku do poprzednich. Zwrócić należy uwagę na sposób przekazania adresu tekstu, jaki się ma wyświetlić, do procedury. Wykorzystywany jest w tym celu stos.

Istotne jest to, że w miejscu wywołania procedur wlinkowywany (nie po polskiemu) jest adres procedury, a nie jej ciało. Program zyska na objętości, lecz w zamian uzyskamy możliwość udostępnienia wybranych procedur innym składowym programu...

Autor zachęca do przeczytania i zrozumienia powyższych rozdziałów. Jako motto w chwilach zwątpienia niechaj Wam służy bardzo mądre przesłanie, którego autorstwa nie znam:

Próbując dosięgnąć gwiazd możesz nie chwycić ani jednej, ale robiąc to zyskujesz pewność, że to co pozostanie w Twojej dłoni nigdy nie będzie garścią błota...



Wyszukiwarka

Podobne podstrony:
asm skrot prezentacji
EMP7700 ASM E B SM
asm z5 psp n
prog w asm podstawy
asm, BIOS INT
asm BIOS INT
asm
Asm i C dla 8051 Nieznany (2)
asm state of the art 2004 id 70 Nieznany (2)
asm z7 dir
asm INT21
asm lin sys
Linux asm lab 07 (Wprowadzenie do Linux'a i Asemblera )
avr asm id 73849 Nieznany (2)
Creating a COM object in ASM
asm kolokwium #1
Programowanie w C i ASM programatorem BASCOM
prog w asm koprocesor

więcej podobnych podstron