arch2, Studia, Assembler


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 (programu nierealokowalnego)

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 deklaracji 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...

6.8. Przykład dodatkowy

W poniższym przykładzie podany zostanie sposób odczytania ciągu znaków z klawiatur. Aby tego dokonać, należy zadeklarować w ściśle określony sposób zmienną, która rzeczony ciąg znaków będzie przechowywała. Robi się to w sposób następujący:

.data

buf db length

db whatever

db length dup (`0')

gdzie:

length - liczba całkowita oznaczająca maksymalną liczbę wprowadza

nych znaków (włącznie z enterem)

whatever - dowolna wartość, która i tak zostanie zmodyfikowana po

wywołaniu funkcji (funkcja 0ah przerwania 21h) odczytu ciągu znaków w ten sposób, że zostanie tu zapisana liczba faktycznie odczytanych znaków (bez entera)

length dup (`0') - `zrobienie' (znowu nieładnie stylistycznie) miejsca w pamięci

na ten ciąg znaków

Natomiast w przykładowym programie będzie to wyglądało w sposób następujący:

.model small

.stack 512

.data

text db `Podaj ciag znakow (<=5): $'

ciag db 6

db 0

db 6 dup (`0')

.code

;--- ustalenie segmentu danych

mov ax,@data ; <=> mov ax,seg text

mov ds.,ax

;--- wypisanie tekstu zachęty

lea dx,text ; <=> mov dx,offset text

mov ah,09h

int 21h

;--- odczyt ciągu znaków z klawiatury - para rejestrów DS.:DX musi wskazywać miejsce ; w pamięci, gdzie znajduje się zmienna buforowa zadeklarowana w odpowiedni sposób

lea dx,ciag ; <=> mov dx,offset ciag

; rejestr ds. jest już wcześniej ustalony

mov ah,0ah

int 21h

;--- zakończenie programu

mov ah,4ch

int 21h

end

Przed uruchomieniem tego programu warto się zastanowić, w jaki sposób można potem dostać się do tego, co się wprowadziło. Otóż:

  1. Pod adresem [ciag+1] znajdziemy po wprowadzeniu czegokolwiek z klawiatury liczbę określającą ile faktycznie znaków wprowadzono (więcej niż 5 się nie da).

  2. Od adresu [ciag+2] znajdziemy kolejno kody ASCII wprowadzonych znaków. Jeżeli np. z klawiatury wprowadzimy 12345, to w pamięci będzie sytuacja:

[buf+1] = 5 ; liczba znaków

[buf+2] = 49 ; '1'

[buf+3] = 50 ; '2'

[buf+4] = 51 ; '3'

[buf+5] = 52 ; '4'

[buf+6] = 53 ; '5'

[buf+7] = 13 ; kod entera

Widać więc, że aby wprowadzona liczba była faktycznie liczbą dziesiętną lub jakąkolwiek inną, należy dokonać konwersji polegającej w dużym uproszczeniu na (w przypadku systemu do dziesiętnego włącznie) odjęciu od każdego wprowadzonego bajtu liczby 48, a następnie na wymnożeniu jej z podstawą systemu w potędze odpowiadającej pozycji poszczególnych wprowadzonych cyfr. To jest naprawdę ważne.

6.9. Elementy składni programu realokowalnego

W rozdziale 6.3. zaprezentowana została składnia programu assemblerowego w wersji nierealokowalnej, to znaczy w takiej wersji, w której model pamięci determinuje z góry maksymalny rozmiar pamięci na dane program i stos. Gdyby się okazało, że pamięci tej potrzeba więcej, program należałoby assemblować i linkować ponownie w innym modelu pamięci.

Program w wersji realokowalnej ma tę cechę, że ilość miejsca potrzebnego na program, dane i stos jest obliczana w trakcie procesu assemblacji i linkowania (konsolidacji) i zawsze jest przydzielona w potrzebnym wymiarze. W najprostszym przypadku budowa programu w wersji jest następująca:

dane segment - segment danych

.. - tutaj kolejne deklaracje zmiennych

dane ends

sts segment stack 'stack' - segment stosu

db ROZMIAR_STOSU dup(0) - zarezerwowanie pamięci na stos

sts ends

program segment - segment kodu

assume cs: program, ds: dane, ss: sts - powiązanie rejestrów segmentowych z

odpowiednimi segmentami

start:

.. - tutaj program

program ends

end start

W powyższym przykładzie pokazano jeden z kilku sposobów konstrukcji pliku źródłowego dla realokowalnej wersji programu. Pogrubioną czcionką wyróżnione zostały niezbędne elementy programu należące do słów kluczowych assemblera, natomiast kursywa stwarza pole do popisu dla inwencji twórczej programistów, bowiem są to nazwy części składowych programu, które mogą być zupełnie dowolne. Poniższy przykład ilustruje składnię programu assemblerowego w wersji realokowalnej.

;--- segment danych

dane segment

tekst db 'ala ma kota$'

dane ends

;--- segment stosu

sts segment 'stack'

db 256 dup(0)

sts ends

;--- segment kodu

program segment

assume cs:program, ds: dane, ss: sts

start:

;--- ustalenie zawartości rejestru DS

mov ax,seg tekst

mov ds,ax

;--- obliczenie adresu efektywnego zmiennej tekst (przesunięcia od początku segmentu)

lea dx,tekst

;--- wywołanie funkcji 09h przerwania 21h (wypisanie ciągu znaków na ekranie)

mov ah,9

int 21h

;--- zakończenie programu z kodem wyjścia 0 (al)

mov ah,4ch

mov al,0

int 21h

program ends

end start

6.10. Program typu com

Program typu com ma inną budowę, niż program typu exe. Jest kilka sposobów na napisanie programu w wersji com. Dwa z nich zaprezentuję poniżej.

Przykład 1.

program segment

assume cs:program, ds:program

org 100h

start:

lea dx,tekst

mov ah,9

int 21h

mov ah,4ch

mov al,0

int 21h

;--- deklaracje zmiennych

tekst db 'ala ma kota$'

program ends

end start

Przykład 2.

program segment

assume cs:program, ds:program

org 100h

start: jmp main

wypisz proc

lea dx,tekst

mov ah,9

int 21h

ret

wypisz endp

koniec proc

mov ah,4ch

mov al,0

int 21h

koniec endp

main proc

call wypisz

call koniec

main endp

;--- deklaracje zmiennych

tekst db 'ala ma kota$'

program ends

end start

Wersja programu com z przykładu 2. jest bardziej użyteczna.

UWAGA:

Przypominam, że linkowanie programów com odbywa się poleceniem "tlink /t prog".

6.11. Na sam koniec

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 niestety nie znam:

Zawsze próbuj dosięgnąć gwiazd. Nawet jeżeli nie chwycisz ani jednej, to co pozostanie w Twoich rękach nigdy nie będzie garścią błota...



Wyszukiwarka

Podobne podstrony:
arch, Studia, Assembler
porownanie, Studia - informatyka, materialy, Assembler
omki, Studia - informatyka, materialy, Assembler
assembler 1, Edukacja, studia, Semestr IV, Architektura Systemów Komputerowych, Projekt, Projekt 1
noweasmy, Studia - informatyka, materialy, Assembler
Assembly, Studia, Podstawy Robotyki I
Studia slajdy1
assembler
Studia slaidy
oszustwa studia cywilne
Mazowieckie Studia Humanistyczn Nieznany (11)
Mazowieckie Studia Humanistyczne r2001 t7 n2 s157 160
Assembler ENG
Mazowieckie Studia Humanistyczne r1996 t2 n1 s165 173
Mazowieckie Studia Humanistyczne r1998 t4 n1 s79 101
Mazowieckie Studia Humanistyczn Nieznany (14)
Mazowieckie Studia Humanistyczne r1997 t3 n1 s290 292
Mazowieckie Studia Humanistyczne r1996 t2 n1 s113 126
Assembly Language for Kids Commodore 64 Addendum

więcej podobnych podstron