Środowisko Assemblera.pdf

(2748 KB) Pobierz
Microsoft Word - „rodowisko Assemblera.doc
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
WYŁĄCZNOŚĆ DO PUBLIKOWANIA TEGO TŁUMACZENIA
POSIADA RAG oraz P & S
HTTP://WWW.R-AG.PRV.PL
http://www.win32asm.civ.pl/
„THE ASSEMBLER ENVIRONMENT”
tłumaczone by KREMIK
wankenob@priv5.onet.pl
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
Środowisko Assemblera
Chcę wprowadzić podstawowe idee dotyczące języka assemblera i jak odnosi się on do naszego systemu..
Będziemy również sprawdzali narzędzia dla programistów assemblerowych i jak najlepiej z nich korzystać. W
końcu, zobaczysz pewne pliki wsadowe DOS’a, które uczynią proces tworzenia końcowego programu
łatwiejszym.
Jeśli jesteś kompletnym nowicjuszem co do języka assemblera i nie masz dużego doświadczenia z niskimi
poziomami swojego PC, wtedy pewne fragmenty materiału mogą być za trudne. Nie martw się! Będę ostrożnie
wykładał wszystkie informacje razem, często odnoszące się w tył, wiec staniesz się bardziej doświadczony. Co
może nie być teraz dosyć jasne, stanie się jeśli nabierzesz więcej doświadczenia. Na razie pomyśl o tym jak o
szybkim marszu .
Rozdział 1...
Rozdział 2...
Rozdział 3...
Te pierwsze trzy Rozdziały odsłaniają podstawy środowiska Assemblera i pokazują jak możesz użyć go do
tworzenia programów. Jeśli możesz stosować Assemblerów takich jak MASM i TASM i z pomocą moich
przykładów powinieneś umieć zastosować oba standardy assemblerów bardziej wydajnie. Biblioteki modułów
wynikowych uczynią twoje życie łatwiejszym kiedy przyjdzie do tworzenia dużych programów wymagających
kilku języków programowania i pomóc Ci połączyć moduły stworzone przez różne kompilatory. Plik wsadowe
jakie wprowadzę powinny pomóc zautomatyzować proces ustawiania i stosowania komponentów assemblera.
Przechodząc teraz do początku Twojego programowania w języku assemblera. Używamy takiego czegoś jak
pętle i skoki.
• jak algorytm jest tłumaczony na instrukcje
• jak sterujemy wykonaniem tych instrukcji
Nauczmy się jak stworzyć nasz pierwszy, prawdziwy program, a potem zobaczymy jego wykonanie pod
CodeView, przyglądając się jak współdziała z systemem.
Rozdział 4...
Rozdział 5...
Rozdział 6...
Przypatrzymy się różnym metodom sterowania przepływem programu, aby połączyć to w użyteczne programy.
Pomyślimy o flagach w CPU i roli jaką odgrywają w sterowaniu programem. Zobaczymy jak instrukcje JMP,
CMP i Loop tworzą rozgałęzienia i pętle w assemblerze. Wynikiem tego wszystkiego jest to, że będziemy mogli
stworzyć programy używające pamięci do przechowywania i działania na danych i uzyskiwać dostęp do
ważnych informacji systemowych.
Wprowadzenie do rozkładu pamięci, podstawowe zasady jej adresowania i dostępne narzędzia dla definiowania
i sterowani polami pamięci. Wyjaśnię koncepcje segmentu i offsetu. Wynikiem tego wszystkiego jest to ,że
będziesz mógł stworzyć programy, które używają pamięci do przechowywania i działania na danych i
uzyskujące dostęp do ważnych informacji systemowych.
Rozdział 7...
Rozdział 8...
Rozdział 9...
Popatrzysz jak mikroprocesor oblicza adres efektywny dla obiektów umieszczonych w różnych segmentach
wymagające różnych rejestrów, tak jak i podstawowe typy adresowania. Z MASM 6.x pokochasz uproszczone
dyrektywy oferowane w nowszej wersji. Szablony dla modułów –COM i –EXE powinny dodać kolorytu do
twojego „Tool-Box’a” Zauważ, że wariant –COM jest preferowany dla programów, które mogą być ulokowane
10136683.001.png
wewnątrz jednego segmentu. Teraz wiesz jak dyrektywa EQU zezwala na zarządzanie nazwami dla stałych.,
pomagając poprawić czytelność. Używając podstawowych form adresowania możesz teraz uzyskać dostęp do
obiektów ulokowanych w różnych jednostkach przechowujących - pamięci i rejestrach.
Pamiętaj o twierdzeniu wypowiedzianym przez Nicklausa Wirth’a w Rozdziale 4: Algorytmy + struktura
danych = program. Zerknij czasem do struktury danych po więcej szczegółów. Używając narzędzi omówionych
w poprzednich Rozdziałach, stworzysz rzeczywiście użyteczną strukturę danych, która odzwierciedli dokładnie
sposób informowania jaki jest używany w świecie rzeczywistym
Rozdział 10...
Rozdział 11...
Rozdział 12...
Teraz zobaczysz jak w najwyraźniej nieustruktoryzowany sposób Assembler obsługuje dane i umieszcza na
odpowiedzialność programisty tworzącego swoje własne struktury danych Prawie wszystkie dane mogą być
zdefiniowane jako grupa bajtów, i możemy nimi odpowiednio manipulować. Zobaczysz jak definiować i
przetwarzać ciągi używając kilku wbudowanych funkcji ciągów. Podczas gdy te narzędzia dostarczają prawie
nielimitowanej elastyczności, cena jest większa w zależności od programisty pielęgnującego integralność
danych, zwłaszcza kiedy porównuje silne typu języka wysokiego poziomu takiego jak Pascal.
ROZDZIAŁ I
Assembler jako język programowania
Język Assembler był prawdopodobnie prekursorem wszystkich języków programowania ponieważ był
pierwszym narzędziem, które ulżyło programistom przy działaniu z zerami i jedynkami i umożliwiło im
stosowanie sensownych nazw dla instrukcji i operandów. W rzeczywistości pierwszy Assembler był prostym
systemem dla przedstawiania instrukcji maszynowych z prostymi mnemonikami. Jego główną zaletą było
automatyczne przydzielanie wartości do adresów instrukcji. To znaczy, że nie musiałeś już dłużej zmieniać
wszystkich poleceń skoków po wprowadzeniu jedno bajtowej danej lub instrukcji do programu! Ponieważ jedna
instrukcja assemblera generowała jedną instrukcję, lub jeden element danej, assembler był znany jako język
wzajemnie jednoznacznego poziomu.
Kolejnym etapem było zaprojektowanie bardziej zwartego języka w którym sekwencja instrukcji maszynowych
mogła być reprezentowana przez jedną instrukcję.. Przykładem takiego może być język makr – pozwala
programiście stosować standardowe sekwencje instrukcji znane jako makro polecenia a nawet definiować swoje
własne sekwencje i przechowywać je do późniejszego zastosowania.
Języki te były definiowane jako poziom jeden do wielu , i czasami były znane jako makrogeneratory (co nie jest
do końca poprawne; ostatnie makrogeneratory mogły przekazywać informacje pomiędzy makropoleceniami, a
czasami więcej niż jedna linia tekstu źródłowego generowała część kodu wynikowego) .Ich popularność minęła
dość dawno, i faktycznie są jeszcze czasami używane jako elementy bardziej złożonych języków. Na przykład,
Assembler /370 dla mainframe’ów IBM i wiele assemblerów dla PC kompatybilnych z IBM. Takie jak MASM
mają wbudowany makrogenerator..
Języki szerzej używane dzisiaj to poziom wiele do wielu. To oznacza, że kilka instrukcji kodu źródłowego
tworzy kilka instrukcji maszynowych. Na przykład poniższa instrukcja Pascala
a:= b + c(i)
nie może być przetłumaczona na kod maszynowy bez znajomości dodatkowych informacji o a, b, c i i..
Przekazując tą informację do kompilatora napiszemy coś takiego:
Var a, b :real;
i: Integer;
c: array[1..10] of real;
Możesz zapytać gdzie nowoczesne assemblery mieszczą to wszystko: odpowiedź dla assemblera PC może
wydać się zakasująca – na wszystkich trzech poziomach!
Assembler PC jest:
• Językiem poziomu jeden do jednego ponieważ wprowadza symboliczne oznaczenie dla każdej instrukcji
maszynowej i pozwala ci zdefiniować daną.
• Językiem poziomu jeden do wielu ponieważ ma wbudowany makrogenerator który pozwala ci tworzyć
instrukcje, które tworzą kilka instrukcji maszynowych
• Językiem poziomu wiele do wielu ponieważ późniejsze wersje takie jak MASM 6.0 dodały nowe cechy
takie jak konstrukcje IF – THEN –ELSE lub DO – WHILE, które są powszechne w językach wysokiego
poziomu takich jak C lub Pascal
10136683.002.png
Kod maszynowy a język assembler
Program jest sekwencją poleceń (instrukcji), które komputer wykonuje jedna po drugiej. Wykonanie każdej
pojedynczej instrukcji jest zakończone w czterech krokach, mianowicie:
1. Pobranie instrukcji iż pamięci
2. Zdekodowanieinstrukcji
3. Wykonanieinstrukcji
4. Przejście do następnej instrukcji
Każda instrukcja w programie jest przedstawiana w pamięci jako sekwencja jedynek i zer. Instrukcja która
przesuwa 0 do rejestru BX wygląda tak:
1011 1011 0000 0000 0000 0000
Oczywiście nie jest łatwo napisać (lub odczytać program) w takiej postaci. Język assembler rozwiązuje ten
problem poprzez wprowadzenie mnemoników do przedstawiania każdej instrukcji mikroprocesora, z różnymi
symbolami przedstawiającymi jego rejestry, W związku z tym powyższa instrukcja wyglądała by tak w
assemblerze:
MOV BX, 0
Jest to pewna poprawa.
Każda linia kodu maszynowego odpowiada linii assemblera zapisanej przy użyciu mnemoników. Oczywiście,
nikt (nawet mniejszość zwana hackerami) nie konwertuje programu kodu maszynowego na program jeżyka
assemblera. W rzeczywistości, przeciwnie to prawda. Typowo, program napisany w assemblerze jest tłumaczony
na kod maszynowy, ale całe szczęście nie ręcznie.
Faktycznie, odpowiedniość jeden do jednego nie jest ściśle prawdą. Pewne linie (dyrektywy) w assemblerze nie
mają swoich odpowiedników w instrukcjach w zasemblowanym programie kodu maszynowego. Dyrektywy te
są używane do pokazania jak program assemblerowy powinien być tłumaczony. Poza tym, różne instrukcje kodu
maszynowego mogą odpowiadać jednemu i temu samemu mnemonikowi języka assemblera wykonywanego w
różnych sytuacjach.
Niemniej język assembler daje pełną kontrolę nad każdą instrukcją kodu maszynowego programu .
Assembler jako element oprogramowania
Jako język programowania Assembler dostarcza dużo bardziej złożonego dostępu do zasobów systemowych niż
jakiś inny język. Jak ważna jest to cecha daje odpowiedź czy używasz Assemblera jako oddzielnego języka
programowania lub stosujesz jego unikalne zdolności jako element programów napisanych w innych językach
programowania.
Nie chcę sugerować abyś porzucił wszystkie inne języki programowania i pisał wszystkie swoje programy
wyłącznie w assemblerze. Nie jest to oczywiście najszybszy sposób tworzenia oprogramowania, chociaż tworzy
małe i szybkie programy. Bardziej realistycznym podejściem jest pisanie części twojego programu w
assemblerze i połączenie ich wszystkich za pomocą linkera. Która część programu powinna być napisana w
assemblerze zależy od twojego całkowitego obiektywizmu, ale jest kilka powszechnych powodów do pisania
pewnych modułów w assemblerze, które możesz używać jako przewodnika :
• Można uzyskać dostęp do zasobów systemowych, które nie są bezpośrednio dostępne przez wybrany język
programowania; na przykład Clipper nie dostarcza bezpośredniego dostępu do pamięci video lub pamięci
rozszerzonej.
• Jeśli chcesz uzyskać dostęp do usług DOS lub BIOS ale twój język programowania nie posiada
odpowiedniej, wbudowanej funkcji bibliotecznej.
• Jeśli potrzebujesz programu uruchamianego najszybciej jak to możliwe przy zastosowaniu bardziej
wydajnych instrukcji przy dostępie do pamięci i rejestrów.
Elementy assemblera mogą również być stosowane bez stosowania specjalnego oprogramowania takiego jak
MASM czy TASM. Wiele języków wysokiego poziomu ma teraz wbudowany assembler, który pozwala na
wprowadzenie kodu assemblerowego bezpośrednio do twojego programu, znanego jako assembler wbudowany.
Na tych stronach dam ci praktyczne przykłady obu sposobów używania assemblerów
Tworzenie programów na pierwszy rzut oka
Proces tworzenia programu zaczyna się od zbudowania sekwencji instrukcji znanych jako kod źródłowy. Plik
tekstowy zawierający kod źródłowy jest traktowany jako moduł źródłowy. Kod źródłowy może być napisany w
jakimś innym języku programowania, takim jak Assembler. Pascal, BASIC lub C. Działający program
komputerowy jest sekwencją elementów, które mogą być interpretowane i wykonywane przez procesor.
Ponieważ celem programu komputerowego jest wykonanie Twojego kodu, ta postać programu jest nazywana
kodem wykonywalnym. Plik zawierający kod wykonywalny programu odnosi się do modułu wykonywalnego.
Przekształcenie kodu źródłowego na kod wykonywalny składa się z następujących etapów
Tworzenie modułu źródłowego
Tworzenie jednego lub więcej modułów wynikowych z modułu źródłowego
Linkowanie modułów wynikowych do kodu wykonywalnego.
Ponieważ moduł wynikowy zbudowano, można go uruchomić bezpośrednio, lub pod kontrola debuggera.
Przynajmniej taka jest teoria! W praktyce, różne etapy nie są zawsze ukończone w takim porządku i niektóre
mogą zostać całkowicie opuszczone. Na przykład pewne systemy BASIC lub xBASIC nie budują modułów
wykonywalnych. Zamiast tego, transformują instrukcje programu do postaci wykonywalnej i bezpośrednio
wykonują jedna po drugiej. Chociaż to podejście oznacza, że możemy zachować mały, prosty i szybki
interpreter, zmniejsza szybkość wykonywania programu. Można powiedzieć, że wszystkie programy języka
assemblera są kompilowane do kodu wykonywalnego przy użyciu modułów wynikowych
Kod źródłowy a edytory tekstu
Zaczniemy od przyjrzenia się modułowi źródłowemu. Jest to plik, który zawiera tekst programu w języku
assembler. Możesz stworzyć ten plik używając albo edytora tekstu albo word procesora. Program edytora tekstu
wykonuje całkiem prostą pracę – odczytuje tekst, wprowadza, usuwa lub zmienia miejscami linie, przeszukuje i
zmienia miejscami symbole i tak dalej. Klasycznym przykładem tego jest edytor EDIT MS-DOS 5.
Jeśli już używasz określonego edytora tekstu lub word procesora, wtedy zostań przy nim. Jednakże jest kilka
potencjalnych problemów na jakie musimy używać. Jeśli używasz word procesora takiego jak WordStar lub
WordPerfect musisz zachować swój program assemblerowy jako pliki tekstowe DOS, bez ich formatowania, w
przeciwnym razie wprowadzi specjalne kody formatujące do tekstu, których assembler nie rozumie.
Innym wyborem w późniejszych wersjach MASM jest użycie Programmmer’s Workbench lub PWB. Zaletą tego
jest ,że dostarcza zintegrowanego środowiska , które pozwoli ci stworzyć, edytować, uruchomić, zlinkować i
zdebuggoać pliki źródłowe bezpośrednio z wnętrza edytora. Wadą jest to ,że jest bardziej zoptymalizowany dla
programowania w C i jest duży i wolny.
Moduły wynikowe i kompilatory
Moduł wynikowy jest pośrednim etapem pomiędzy kodem źródłowym a kodem maszynowym. Zawiera
instrukcje maszynowe, które mają rzeczywiste kody operacyjne, ale adresy w tych instrukcjach nie odpowiadają
rzeczywistym adresom w RAM. Różne kompilatory tworzą różne rodzaje modułów wynikowych, ale
najpopularniejszym sposobem adresowania wszystkich instrukcji i danych wewnątrz modułu wynikowego jest
przypuścić, że program jest ładowany pod adres startowy 0. Adresy tak uzyskane odnoszą się do adresów
względnych. Przed uruchomieniem, adresy względne muszą być zamienione z adresami rzeczywistymi, które są
określone poprzez ulokowanie programu w pamięci. Linker, omówiony później na tych stronach wykonuje to
zadanie.
Moduł wynikowy zazwyczaj odpowiada jednej jednostce programowej- albo programowi głównemu albo
podprogramowi. Jeśli twój program nie wywołuje żadnych innych podprogramów, pojedynczy moduł może być
10136683.003.png
po prostu skonwertowany do postaci wykonywalnej i uruchomiony. Jeśli twój program wywołuje inne
podprogramy, musisz znaleźć je i połączyć razem
Związki pomiędzy modułami a programem
Zazwyczaj jest wyraźna różnica pomiędzy programem głównym a jakimś pod programem, chociaż taki sam
moduł może być używany dla różnych celów
Program główny –
moduł, który może być wywołany przez system operacyjny; na przykład, wszystkie zewnętrzne
polecenia DOS’a, takie jak FORMAT, EDIT lub DISKCOPY są programami głównymi.
Podprogram –
moduł, który może być wywołany przez inny moduł; na przykład funkcja SIN zawiera się w
bibliotekach większości kompilatorów
Będziemy również używali terminu „program wywołujący (moduł wywołujący) i program wywołujący
podprogram. Jeśli spojrzysz na diagram, zobaczysz, że pokazuje on związki pomiędzy trzema modułami
programu:
• Programem głównym
• Pierwszym podprogramem
• Drugim podprogramem
Biblioteki obiektów i zarządzanie biblioteką
Jeśli już używałeś systemów języków wysokiego poziomu, takich jak C, BASIC, Pascal lub FORTRAN, spójrz
na pliki dostępne w tym systemie. Niektóre z nich mają prawdopodobnie rozszerzenie .LIB, co oznacza
biblioteki modułów wynikowych. Jeśli nie masz tych plików, nie martw się. Są różne rodzaje bibliotek, które,
chociaż podobne w działaniu, mają różne struktury i konwencje nazewnicze. Na przykład biblioteki tworzone
przez Turbo Pascal są przechowywane jako pliki z rozszerzeniem .TPU a biblioteki dynamiczne używane w
Windows i OS/2 mają rozszerzenie .DLL. Zajmiemy się tymi bibliotekami, które są używane w kompilatorach
Microsoft (C/C++, Pascal i FORTRAN) i mogą być przetwarzane przez inne systemy takie jak Turbo
Assembler, Turbo C/C++ lub Clipper
Specjalny program nazywany zarządcą biblioteki wykonuje trzy główne operacje na bibliotekach modułów
wynikowych:
• Dodaje nowe pozycje do biblioteki
• Usuwa pozycje zawarte w bibliotece
• Zamienia miejscami pozycje w bibliotece
Proces dodawania nowego modułu wynikowego do biblioteki stosuje tworzenie nowej biblioteki i rozszerzenie
istniejącej. Jeśli próbujesz przetwarzać bibliotekę, która w rzeczywistości nie istnieje jeszcze, zarządca
biblioteki automatycznie ją stworzy, używając nazwy określonej przez ciebie. Jeśli jesteś w trybie dialogowym,
będziesz zapytany o potwierdzenie przed stworzeniem biblioteki.
Kiedy dodajesz nowy moduł do istniejącej biblioteki, zarządca biblioteki stworzy nową kopię biblioteki i
włączy wszystkie moduły ze starej do niej. Potem spróbuje włączyć nowy moduł do nowo stworzonej biblioteki,
10136683.004.png
Zgłoś jeśli naruszono regulamin