Assembler.pdf

(237 KB) Pobierz
43622512 UNPDF
Rozdział I
Przed startem…
Wprowadzenie
Ta sekcja zajmuje się elementarnymi pojęciami z zakresy danych CPU i ogólnie programowania. Doświadczeni
programiści mogą zechcieć przeskoczyć ten rozdział.
Bity i bajty
Kiedy programujemy w Asemblerze, konieczna będzie wiedza o bitach, bajtach i słowach. Bit jest najmniejszym
elementem informacji jak może być adresowana. Pojedynczy bit może być oprogramowany jako zero lub jeden.;
dlatego też nie może zawierać wiele informacji. Grupa ośmiu bitów połączonych razem tworzy jeden bajt. Przy
ośmiu bitach połączonych razem możesz przedstawić liczby od zera do 255 lub 256 kombinacji. Jeśli najwyższy
bit bajtu jest używany do identyfikacji liczby jako dodatniej albo ujemnej, wtedy możesz przedstawić liczby od
-128 do +127. Kiedy wyższy bit bajtu jest używany jako flaga dodatni/ujemny, wtedy mówimy o liczbie ze
znakiem. Jest to ważne ponieważ niektóre instrukcje będą używały logiki ze znakiem lub bez znaku. Dwa ośmio
bitowe bajty połączone razem tworzą 16 bitowe słowo. Dla 16 bitów możesz przedstawić liczby od zera do
65535. 8086 jest klasyfikowany jako procesor 16 bitowy. Większość rejestrów jest 16 bitowych, które mogą być
adresowane w trybie 8 bitowym. Większość operacji jest słowami lub orientowanymi bajtami. Słowo ze znakiem
jest z zakresu -32768 do + 32767. Podwójne słowo jest 32 bitowe , co jest równe dwóm słowom lub czterem
bajtom.
BIT |X|
(X może być 0 lub 1)
BYTE |XXXXXXXX|
WORD |XXXXXXXXXXXXXXXX|
Podstawy CPU
CPU jest to central Processing Unit. Wykonuje funkcje poza blokiem pamięci, który może być wywołanym, jego
zakresem adresowania. Kiedy CPU zaczyna wykonywanie instrukcji, ładuje instrukcje danych do swoich
wewnętrznych rejestrów ,zwiększając wskaźnik instrukcji indeksując kolejną instrukcję do wykonania po
zakończeniu instrukcji wcześniejszej. Zwróć uwagę ,że pewne instrukcje resetują zawartość rejestru wskaźnika
instrukcji aby wymusić wykonanie programu modyfikując standardową ścieżkę kolejnej instrukcji. Jest to
nazywane skokiem programu lub rozgałęzieniem. CPU 8086 zazwyczaj działa na danych bajtowych lub o
rozmiarze słowa. CPU 8086 ma 20 bitową szynę adresową, która pozwala adresować ponad milion bajtów
pamięci bez[pośredniej.
Podstawy programowania
Ogólne szkic dla standardowego programu jest jak następuje:
1.odczyt danych z urządzenia (takiego jak plik, klawiatura, zmiennej pamięci, zegar, myszka itp.)
2.potem badamy lub modyfikujemy dane jeśli to konieczne
3.potem zapisujemy dane do urządzenia takiego jak plik, wyświetlacz, zmienna pamięci, port dźwięku itp.)
Program w języku Asemblera jest to lista instrukcji w pliku z kodem źródłowym, który może być skompilowany
do kodu wykonywalnego, który może zrozumieć CPU. Po wygenerowaniu kodu wykonywalnego, powinieneś
móc załadować plik z kodem do pamięci komputera i wykonać go W języku Asembler, wiele instrukcji jest
zapisywanych wraz z kontrolowaniem aktywności CPU. Możesz również pisać dyrektywy dla kompilatora i
komentarze o zadaniach procedur. Program może współpracować z innym urządzeniem, np. koprocesorem
matematycznym, kontrolerem przerwań, urządzeniami zegarowymi itp. CPU 8086 ma wiele rejestrów, które są
wykorzystywane do wykonywania różnych zadań. Jest 14 dostępnych rejestrów dla kontroli przez programistę.
Każda instrukcja która jest wykonywana w programie wpływa na jeden lub więcej rejestrów CPU. Nawet
instrukcja NOP zmienia rejestr wskaźnika instrukcji. Pewne rejestry mogą być używane do przechowywania
danych. Inne rejestry mogą być używane do indeksowania danych. Z tego powodu jest ograniczona liczba
rejestrów używanych do indeksowania rejestrów przechowujących dane w danym czasie.
Rozdział II
Rejestry CPU
Wprowadzenie
Sekcja ta omówi programowalne rejestry CPU. Język Asembler musi zapoznać się z działaniem każdego rejestru
aby programować efektywnie. Pozostałe rejestry są omówione w sekcji na temat pozostałych procesorów
80X86. Poniżej mamy listę 16 bitowych rejestrów i ich odwołań:
AX
Akumulator
FL
Flagi
X|X|X|X|OF|DF|IF|TF|SF|ZF|X|AF|X|PF|X|CF
BX
Indeks bazowy
BP
Wskaźnik bazowy
CX
Licznik
DX
Indeksanych I/O
DI
Indeks przeznaczenia
SI
Indeks źródłowy
SP
Wskaźnik stosu
IP
Wskaźnik instrukcji
CS
Segment kodu
SS
Segment stosu
DS.
Segment danych
ES
Segment dodatkowy
Niektóre rejestry mogą być podzielone i dostępne jako dwa ośmiobitowe rejestry dla operacji bajtowych. Są one
dzielone jak następuje:
AH
AX
Wyższy bajt
AL.
AX
Niższy bajt
BH
BX
Wyższy bajt
BL
BX
Niższy bajt
CH
CX
Wyższy bajt
CL
CX
Niższy bajt
DH
DX
Wyższy bajt
DL
DX
Niższy bajt
AX i AL są Akumulatorem
AX=AH + AL jest 16 bitowym odnośnikiem dla akumulatora., AL jest 8 bitowym odniesieniem. AL. jest niższą
połówką AX podczas gdy AH jest wyższą połówką. Akumulator jest podstawowym rejestrem danych.
Większość instrukcji dla obsługi danych wykonuje się szybciej jeśli dana jest w akumulatorze .
FL rejestr flag
Rejestr Flag jest 16 bitowym rejestrem danych używanym do śledzenia aktywności CPU. Obejmuje on wyniki
logiczne, arytmetyczne i porównania jak również kontrolę przerwań, śledzenie debugowania, flagi kierunku
ciągów itp. Większość instrukcji skoków warunkowych używa zawartości tego rejestru dla określania czy
warunek rozgałęzienia jest prawdą lub fałszem.
Bity flag X|X|X|X\OF|DF|IF|TF|SF|ZF|X|AF|X|PF|X|CF
Pozycja bitu oznaczona X nie jest zdefiniowana dla CPU 8086/8088 ale są zarezerwowane przez Intel dla
używania z procesorami z tej serii.
OF flaga przepełnienia
Ten bit jest ustawiony jeśli ostatnie manipulowanie danymi spowodowała zmianę najwyższego bitu.
DF flaga kierunku
Ten bit jest używany przez CPU aby zdecydować o kierunku działania ciągu. Wyzerowanie tego bitu spowoduje,
że działanie ciągu do przodu a ustawienie tego bitu powoduje działanie ciągu w tył.
IF flaga przerwania
Ten bit może być ustawiony lub wyzerowany przez programistę aby zablokować lub zezwolić na wystąpienie
zamaskowanego przerwania.
TF flaga śledzenia
Ten bit jest używany w trybie debuggowania dla krokowego przechodzenia przez logikę programu.
SF flaga znaku
Ten bit jest resetowany przez operacje logiczne równe najwyższemu bitowi danych wynikowych.
ZF flaga zera
Ten bit jest ustawiany jeśli ostatnia zmieniona dana stworzyła warunek zerowy.
AF flaga przeniesienia pomocniczego
Bit ten jest używany przez instrukcje logiczne, które działają z danymi typu nibble (cztery bity)
PF flaga parzystości
Bit ten jest resetowany przez ostatnią zmienioną danę dla odzwierciedlenia czy działanie stworzyło parzysty lub
nieparzysty warunek. 1 oznacza parzystość a 0 oznacza nieparzystość
CF flaga przeniesienia
Kiedy dodajemy, bit przeniesienia jest ustawiony jeśli wystąpi przepełnienie. Jeśli odejmujemy, bit jest
ustawiony jeśli mamy pożyczkę bitu ponieważ odejmowanie spowodowało przeskok znaku.
BX indeks bazowy
BX najelastyczniejszym z rejestrów indeksowych. Jest to 16 bitowy rejestr ,który może również być adresowany
w formacie 8 bitowym jako BX (najwyższy) i BL (najniższy) gdzie BX = BH + BL. BX może być dodany do
innego rejestru bazowego dla pracy z bardziej złożonymi indeksami offsetów. Przykłady : [BX+offset],
[BX+SUI+offset],[BX+DI+offset].
BS wskaźnik bazowy
BP jest rejestrem wskaźnika bazowego używanego do indeksowania danych w obszarze stosu. Rejestr ten jest
używany przez wiele kompilatorów dla indeksowania danych w obszarze stosu.
Przykłady:[BP+SI+offset],[BP+DI+offset]
SI indeks źródła
SI jest rejestrem indeksowania źródła używanym przez instrukcje ciągu. Może by z BX lub BP do indeksowania
danych. Przykłady: [SI+BX+offset]
DI indeks przeznaczenia
DI jest rejestrem indeksu przeznaczenia używanym przez instrukcje ciągu. Może być łączony z BX lub BP do
indeksowania danych. Przykłady: [DI+BX+offset]
SP wskaźnik stosu
SP jest rejestrem wskaźnika stosu używanym przez instrukcje push, pop, call, interrupt i return. Zawsze
indeksuje ostatnie słowo odłożone na stos.
CX licznik
CX jest rejestrem licznika używanym przez instrukcje ciągów, repeat i loop
DX rejestr danych, indeks I/O
DX jest rejestrem danych. DX jest tylko używany jako indeks dla funkcji portów I/O. Jest używany dla instrukcji
mnożenia 16 x 16 bitów i instrukcji dzielenia 32 przez 16 bitów. Wynik 16 bitowego mnożenia jest odkładany do
DX:AX gdzie DX przechowuje wyższe 16 bitów a AX przechowuje niższe 16 bitów . Dla dzielenia 32 przez 16
bitów, DX będzie przechowywał modulo danych wynikające z dzielenia.
IP wskaźnik instrukcji
IP jest używany do indeksowania kolejnej instrukcji do wykonania. Jest resetowany przez instrukcje call i jump.
Rejestry adresowania segmentów
CPU 8086 dzieli swoją adresowalną pamięć na cztery obszary. Te cztery obszary to kod, stos dane i dane
dodatkowe. Bieżąca lokacja tych sekcji jest sterowana prze rejestry adresowania segmentu. Architektura 8086
używa tych rozszerzeń do adresowania zakresu CPU> Podstawowy zakres adresowania dla 16 bitowego CPU to
65536 bajtów. Przez dodanie offsetów pamięci segmentowanej do pamięci adresowalnej sprzętu, zakres
adresowania CPU 8086 zwiększa się do 20 bitów lub 1 048 576 bajtów. Jest to wykonywane przez przesunięcie
czterech 16 bitowych rejestrów segmentów o nibble (cztery bity ) i dodanie ich do innych rejestrów
indeksowania aby złożyć 20 bitowy adres rzeczywisty. W tym systemie, CPU może adresować jeden megabajt
pamięci. Jedyna złożoność tego systemu pamięci jest taka ,że jest dzielona na cztery bloki, które mają
maksymalnie 64 KB każdy. To ogranicza aktywność zakresu adresowania CPU do maksymalnie 256 KB za
jednym razem. Ponieważ są dwa 16 bitowe słowa użyte do złożenia adresu, tekst ten używa pojęcia „offset” aby
odnieść się di adresu w niższym 16 bitowym zakresie (0-65535). Odniesienie do części adresowania segmentu,
którym jest górne 16 bitowe słowo, używamy określenia „SEG” lub „segment”
CS segment kodu
Jest używany z rejestrem IP (wskaźnik instrukcji) do indeksowania kolejnej instrukcji dla wykonania logiki
programu. Oto jak CPU wylicza adres kodu ze wskaźnikiem instrukcji:
IP
|X|X|X|X||X|X|X|X||X|X|X|X||X|X|X|X|
+CS |X|X|X|X||X|X|X|X||X|X|X|X||X|X|X|X|
=adres rzeczywisty |X|X|X|X|X||X|X|X|X||X|X|X|X||X|X|X||X|X|X|X|
Jeśli IP=7 a CS=3, wtedy adres rzeczywisty = 37H jak pokazano:
IP
|0|0|0|0||0|0|0|0||0|0|0|0||0|1|11|
+CS
|0|0|0|0||0|0|0|0||0|0|0|0||0|0|1|1|
= adres rzeczywisty
|0|0|0|0||0|0|0|0||0|0|0|0||0|0|1|1||0|1|11|\
DS. segment danych
Jest używany jako podstawowy obszar danych. Jest indeksowany przez BX, SI <DI (kiedy Di nie wykonuje
instrukcji ciągu) i offset bez rejestru indeksu.
SS segment stosu
Jest używany jako obszar danych stosu. Indeksowany jest przez SP i BP .Zwróć uwagę ,że kiedy jest używany
BX z BP w wyliczeniu offsetu adresu, wtedy jest używany segment SS.
ES ekstra segment
Jest używany jako dodatkowy obszar danych. Indeksowany jest przez DI podczas wykonywania instrukcji ciągu
jako adresu docelowego.
Rozdział III
Elementy instrukcji języka asemblera
Wprowadzenie
Sekcja ta omawia podstawową strukturę instrukcji języka asemblera. Będzie wiele przykładów kodowania w tej
książce. Przykłady kodów będą rozróżniane poprzez unikalny rodzaj czcionki. W standardowych instrukcjach
języka asemblera, są cztery pola. Pola są zazwyczaj oddzielone przez spację lub znak tabulatora. W wielu
instrukcjach, są ukryte pola. Generalnie mogą być przedstawiane w postaci poniższych przykładów:
Etykieta
Operator
Dane
Komentarz
Pole
Pole
Pole
Pole
;jeśli AH nie jest zerem, podprogram ten dodaje 30H do AL.
Add_AL_30:
Proc
near
cmp
ah,0
;porównuje AH z zerem
jnz
add_al_0
;skok jeśli nie zero
add
al., 30H
;instrukcja dodaje 30 do AL.
add_al_0:
;powrót do calleru
Ret
Pole etykiety zaczyna się przed innymi polami. Pole to jest używane dla zdefiniowania nazw, które tworzy
programista aby odnieść się to tego położenia w programie. Oto trzy sposoby definiowania etykiety:
1. Zakończenie etykiety znakiem średnika ( ; )
2. Użycie instrukcji PROC jeśli etykieta służy procedurze
3. Użycie instrukcji LABEL jeśli etykieta jest dla struktury danych lub typu danych (NEAR, FAR, BYTE,
WORD,DWORD, FWORD, PWORD, QWORD, TBYTE, DATAPRT, CODEPTR)
Pole operatora przychodzi po polu etykiety a przed polem danych. Zmusza kompilator lub CPU do zrobienia
czegoś. Pole to jest często wypełniane mnemonikami języka. Pole danych przychodzi po polu operatora a przed
polem komentarza. Jeśli pole operatora wymaga zmiennych danych , wtedy przychodzi dana. Może nie być
wielu zmiennych danych lub operandów dla operacji. Kiedy są używane dwie zmienne danych z większością
instrukcji 8086, pierwszy operand jest operandem przeznaczenia a drugi operandem źródła.
Przykłady:
Zgłoś jeśli naruszono regulamin