2. Systemy liczbowe
Do programowania w Assemblerze przydatna będzie na pewno
wiedza o dwóch dodatkowych systemach liczbowych (prócz dziesiętnego) takich jak:
dwójkowy (binarny), szesnastkowy (heksadecymalny).
Opiszę krótko te dwa systemy:
binarny – podstawą systemu jest są dwie cyfry: 0 i 1. W tym systemie działa
komputer, w tym systemie jest zapisywany kod programu. Liczby w tym systemie
przyjęło się zapisywać z literą b na końcu (np. 10001011b).
heksadecymalny – podstawą systemu są cyfry od 0 do 9 i litery od A do F (w sumie
szesnaście znaków). Dla człowieka o wiele bardziej wygodny od systemu binarnego.
Liczby w tym systemie przyjęło zapisywać się z literą h na końcu (np. 23E0B3h).
To wszystko na temat systemów, jak ktoś chce może doczytać coś więcej o nich, a
także nauczyć się je ręcznie przeliczać. Jednak programując szybciej i wygodniej
jest przeliczać te systemy za pomocą kalkulatora. Dlatego jedziemy dalej.
3. Jednostki informacji pamięci komputerowej
Bit – najmniejsza część danych. Przyjmuje wartość 0 lub 1.
Bajt – jest to 8 bitów. Jego maksymalna wartość to 255d.
Word (Słowo) – 2 bajty, czyli 16 bitów. Maksymalna wartość to 0FFFFh (lub
65535d).
Double-Word (Podwójne słowo) – Dwa słowa, czyli 4bajty (32 bity).
Maksymalna wartość to 0FFFFFFFF (lub 4294967295d).
Quad-Word (Poczwórne słowo) – Cztery słowa, czyli 8 bajtów (64 bity).
Kilobajt – 1024 bajty.
Megabajt – 1024 kilobajty, 1048576 bajtów.
3.1 ZMIENNE
zmienna1 db
0 ;zmienna o rozmiarze 1
bajta
zmienna2 dw 0
;zmienna o rozmiarze pojedyńczego słowa (2 bajtów)
zmienna3 dd 0
;zmienna o rozmiarze podwójnego słowa (4 bajtów)
zmienna4 pw 0
;zmienna o rozmiarze potrójnego słowa (6 bajtów)
zmienna5 dq 0 ;zmienna o rozmiarze poczwórnego słowa (8 bajtów)
zmienna6
dt 0 ;zmienna o
rozmiarze dziesięciu bajtów (DT - Define Ten (bytes))
zmienna7 db 256
dup(0)
;dyrektywa dup (duplicate) powoduje zarezerwowanie pamięci
o podanym rozmiarze (w tym przypadku 256 bajtów) i wypełnienie go podaną
wartością (w tym przypadku zerami).
4. REJESTRY PROCESORA
Teraz będzie dużo teorii, którą warto przeczytać, ale nie ma sensu kuć na pamięć, z czasem się zapamięta :)
Rejestry są to komórki pamięci wewnątrz procesora służące mu do wykonywania różnych operacji. Warto wspomnieć, że operacje na rejestrach są o wiele szybsze niż na zmiennych w pamięci. Rejestry ogólnego przeznaczenia są cztery (EAX, EBX, ECX i EDX). Mają one po 32 bity (4 bajty). Każdy z nich dzieli się na dwie części po 16 bitów (części te nazywają się HIGH-WORD i LOW-WORD). Weźmy na przykładzie rejestru EAX: Niższa część (LOW-WORD) to rejestr AX, który dzieli się znów na dwa rejestry 8 bitowe: AH i AL. Warto wspomnieć też, że te rejestry możemy używać do czego chcemy, ale każdy z nich ma swoje specjalne przeznaczenie.
Lecz to nie wszystkie rejestry. Są jeszcze dwa rejestry indeksowe (EDI i
ESI), które dzielą się na DI i SI. Używa się ich do operacji na łańcuchach (np.
na tekście). ESI przechowuje źródło (ang. Source), a EDI miejsce docelowe (ang.
Destination). EBP i ESP to natomiast rejestry wskaźnikowe pierwszy z nich służy
do adresowania, drugi przechowuje wskaźnik wierzchołka stosu.
Podobnie jak wyżej załączam ilustracje:
Pozostałe rejestry to:
- rejestry segmentowe (16 bitowe): CS (Code Segment), DS (Data Segment), ES
(Extra Segment), SS (Stack Segment), FS, GS.
- rejestr flag: EFLAGS
- rejestry koprocesora: ST0…ST7, do operacji na liczbach zmiennoprzecinkowych.
- EIP - rejestr zawierający adres aktualnie wykonywanej instrukcji.
To już wszystkie rejestry, które by nas interesowały.
5. PRZYKŁADOWY PROGRAM
.model
tiny
.code
org 100h
start:
mov ah,9
mov dx,offset
info
int 21h
mov ah,0
int 16h
mov ax,4C00h
int 21h
info db "PWSZ
KROSNO $"
end start
5.1 OPIS INSTRUKCJI PROGRAMU
Pierwsza instrukcja naszego programu to
mov. Jest to instrukcja
kopiowania. Kod który widzimy nadaje rejestrowi
ah wartość
9.
Inne przykłady użycia instrukcji mov:
mov
ax, 0
;rejestr ax przyjmuje wartość zero
mov zmienna,
123 ;zmienna o nazwie
"zmienna" przyjmuje wartość 123
mov ax,
cx
;rejestr ax przyjmuje wartość rejestru cx
mov zmienna,
ax ;zmienna przyjmuje
wartość rejestru
mov ax,
offset zmienna ;w rejestrze
ax będzie adres do tego co jest w zmiennej
;załóżmy, że zmienna ma wartość 125. Zatem pisząc:
;mov
ax, zmienna rejestr ax będzie miał wartość 125
;jeżeli natomiast napiszemy:
;mov ax, offset zmienna to rejestr
ax będzie miał adres
;do tej wartości w pamięci.
;offset używamy np. gdy chcemy do rejestru dać adres jakiegoś
;łańcucha znaków, normalnie tekst by się nie zmieścił w rejestrze
;więc dajemy adres do tego tekstu.
mov zmienna1, zmienna2
;ten zapis jest BŁĘDNY, gdyż nie można skopiować
wartości
;ze zmiennej do innej zmiennej.
;zatem trzeba posłużyć się rejestrem pomocniczym (skopiować
;wartość do tego rejestru, a potem do zmiennej) lub
;odłożyć wartość na stos, a potem dać do innej zmiennej
;(o działaniach na stosie będzie później).
;skopiowanie wartości ze zmienna1 do zmienna2 przy pomocy rejestru pomocniczego
mov ax,
zmienna1 ;ax przyjmuje
wartość zmienna1
mov zmienna2,
ax
;zmienna 2 przyjmuje wartość ax
;skopiowanie wartości ze zmienna1 do zmienna2 przy użyciu stosu
push zmienna1
;odłóż zmienna1 na stos (push)
pop zmienna2
;zdejmij wartość ze stosu i daj do zmienna2 (pop)
Wracając do naszego programu. Następna linijka to
mov dx,offset
info.
Kopiuje ona adres pod którym znajduje się tekst
"PWSZ
KROSNO $" do rejestru
dx.
Po czym następuje wywołanie przerwania o numerze 21h.
Potem jest przerwanie int 16h/ah=0, które czeka na naciśnięcie klawisza (zatrzymuje ono program, abyśmy mogli przeczytać wypisany tekst).
A po nim przerwanie kończące program (tj. int 21h/ax=4C00h).
Pod tym wszystkim widzimy zadeklarowaną zmienną o nazwie
info, która zawiera ciąg znaków
"PWSZ
KROSNO $".
Zmienna jest wielkości 13 bajtów (wszystkie znaki razem ze spacjami i znakiem
kończącym $).
Dyrektywa db użyta właśnie tam
definiuje odpowiednią ilość bajtów (db - define byte).
5.2 KORZYSTANIE Z DOKUMENTACJI Wszystko się zgadza, przerwanie numer
21h z parametrem
09h w rejestrze
ah.
Jeżeli chcemy programować to musimy nauczyć się korzystać z
dokumentacji. Przecież cały czas nie będzie przy nas osoba, która przetłumaczy
nam na język polski dokumentacje i opisze dokładnie co funkcja robi. Zatem teraz
pokażę, jak łatwo dowiedzieć się co dane przerwanie wykonuje, bo nie znającej
przerwań osobie numer 21h dużo nie mówi.
Zatem przeanalizujmy powyższy kod korzystając z dokumentacji z Internetu.
Pod tym adresem jest tablica przerwań wraz z opisem:
http://www.ctyme.com/intr/int.htm
Wchodzimy na tą stronę i klikamy na link
21h (gdyż
taki jest numer pierwszego przerwania z naszego programu:
int
21h).
Widzimy bardzo długą listę przerwań, jak teraz znaleść to co jest w naszym
programie?
Odnajdziemy je po parametrach, widzimy, że do rejestru
ah kopiowana jest wartość
9, zatem szukamy takiej linijki na stronie:
Klikamy w link i naszym oczom ukazuje się opis przerwania:
AH = 09h
DS:DX -> '$'-terminated string
Return:
AL = 24h (the '$' terminating the string, despite official docs which
state that nothing is returned) (at least DOS 2.1-7.0 and
NWDOS)
Notes: ^C/^Break are checked, and INT 23 is called if either pressed. Standard
output is always the screen under DOS 1.x, but may be redirected under DOS 2+.
Under the FlashTek X-32 DOS extender, the pointer is in DS:EDX
Najpierw tłumaczymy nagłówek: WRITE STRING TO STANDARD OUTPUT
- WYPISZ TEKST DO STANDARDOWEGO WYJŚCIA
Czyli już wiemy, że to przerwanie wypisuje tekst do standardowego wyjścia (u nas
jest to konsola).
Następnie widzimy parametry jakie musimy podać:
Do rejestru ah musimy dać
wartość 9, a do
dx adres naszego tekstu
zakończonego znakiem $.
Niżej po Return: widzimy opisane co przerwanie zwraca. Zwraca nam wartość
24h w rejestrze
al. Tutaj akurat zwracana
wartość nas nie interesuje, ale np. przerwanie pobierające aktualną datę, zwróci
nam tą datę do jakiegoś rejestru i wtedy będziemy musieli na to zwrócić uwagę.
7. KOMPILACJA KODU ŹRÓDŁOWEGO DO PLIKU WYKONYWALNEGO (*.com)
kompilacja.html (wymagany Flash Player).
D.F.