Asembler x86/Podstawy
W tym rozdziale poznasz podstawy asemblera, które są w całości wspólne dla wszystkich asemblerów.
Instrukcje
edytujInstrukcje (nie mylić z funkcjami!), których będziemy używać w asemblerze są bezpośrednio tłumaczone na "język" procesora. Oznacza to, że każda instrukcja, której użyjemy w kodzie, wywołuje konkretną, niepodzielną na mniejsze (przynajmniej w większości przypadków) reakcję procesora. W językach wysokiego poziomu nie operujemy na takim poziomie. Pozornie proste "wyższe" konstrukcje językowe są zamieniane na kilka, kilkanaście instrukcji procesora przez co w efekcie nie mamy bezpośredniej kontroli nad wynikowym kodem. Ograniczenie to nie dotyczy nas, gdy programujemy z użyciem Asemblera. Lista instrukcji procesora znajduje się w rozdziale Instrukcje. Jak już pewnie spostrzegłe(a)ś, jest ich mnóstwo, zapamiętanie wszystkich z nich jest bardzo czasochłonne; najłatwiej przychodzi w praktyce. Każdej instrukcji używa się wg schematu:
instrukcja parametr1, parametr2, parametr3
Jako parametry (zamiennie, możemy je nazywać argumentami lub operandami) możemy przekazywać: rejestry, adresy do pamięci i nazwy symboliczne, przy czym ich liczba jest zależna od użytej instrukcji i waha się w przedziale od 0 do 3 argumentów. Niektóre instrukcje występują w kilku(nastu) wersjach o identycznej nazwie, z różną liczbą parametrów. Instrukcje powinny znajdować się jedynie w obszarach kodu definiujących segmenty. Używanie ich poza nimi może być kłopotliwe.
Etykiety
edytujEtykiety (ang. label) istnieją jedynie na poziomie kodu asemblerowego. Po asemblacji nie pozostaje po nich żaden ślad. Służą do nazywania konkretnych adresów w pamięci. Znacznie zwiększają czytelność i elastyczność kodu, gdyż operowanie na liczbach określających adresy w pamięci jest skrajnie niewygodne. Aby przydzielić etykietę do adresu, korzystamy z poniższego prostego schematu:
etykieta:
Etykieta musi znajdować się na początku linii i być niepoprzedzona niczym innym. Gdy już połączymy to z naszą dotychczasową wiedzą o korzystaniu z instrukcji, możemy napisać prosty przykład:
etykieta: movl %ecx, %eax
Od tej pory, gdy będziemy chcieli odnieść się do tego adresu (np. gdy zechcemy przeskoczyć w wykonaniu naszego programu bezpośrednio w miejsce z naszą instrukcją mov), możemy napisać po prostu:
jmp etykieta
zamiast podawać cyferki adresu w pamięci (instrukcja jmp modyfikuje rejestr EIP, przez co procesor "przeskakuje" do innego kodu; więcej o tej instrukcji w rozdziale Funkcje). Dodatkowo, poprzedni kod, który zdefiniowaliśmy, jest równoznaczny z poniższym:
etykieta:
movl %ecx, %eax
Jak zapewne zauważyłe(a)ś, definicja etykiety podczepia się automatycznie pod najbliższą linijkę (jednak nie zawsze obowiązuje ta zasada!).
Komentarze
edytujKomentarz jest to po prostu notatka mająca ułatwić zrozumienie danego fragmentu kodu innym, którzy będą go czytać oraz przede wszystkim temu, kto go napisał. Jeśli programista daruje sobie komentowanie kodu, orientowanie się w nim będzie zajmowało mu więcej czasu, lub też zajmie mu to nieskończoną ilość czasu, gdyż z obłędem w oczach skasuje całą swoją pracę nie mogąc zrozumieć ani jednej linijki. Komentarze istnieją jedynie na poziomie kodu źródłowego, po kompilacji nie pozostaje po nich żaden ślad. Aby uczynić dowolny tekst komentarzem i tym samym wyłączyć go z procesu asemblacji, należy poprzedzić go średnikiem. Średnik zamienia w komentarz wszystko, co znajduje się za nim, aż do końca linii.
movl %edx, %eax ; to jest komentarz
Asembler MASM umożliwia jeszcze jedną metodę komentowania:
comment granica komentarz granica
Przy czym jako granica wstawiamy dowolny znak np.
comment ; to jest komentarz to także jest komentarz ; a to już nie
GNU Assembler z kolei ma zupełnie inną składnię komentarzy. Aby objąć dowolny blok komentarzem, należy umieścić go między /* oraz */ (zapewne ten sposób komentowania jest znajomy dla programistów C). W przypadku tego asemblera, dozwolone jest również używanie znaku # , który ma identyczne działanie jak znak ; (średnik) w przypadku innych asemblerów. np.
# to jest komentarz
/* to jest komentarz
to też jest komentarz */
to już nie!
Struktura kodu asemblera
edytujKod asemblerowy to instrukcje, pogrupowane w segmenty. To w nich znajduje się cała esencja naszego programu. Poza nimi definiuje się raczej jedynie różne struktury, makroinstrukcje, które same w sobie nie pozostawiają żadnego śladu w zasemblowanym kodzie. Mimo to asemblery są bardzo elastyczne i pozwalają na umieszczanie instrukcji wszędzie, nawet poza obszarami definiującymi segmenty, przy czym stale zachowany jest porządek góra-dół, tzn. to co znajduje się wyżej w kodzie, jest wyżej w pliku wykonywalnym (tzn. bliżej jego początku); zaś to, co znajduje się niżej w kodzie, jest niżej w pliku wykonywalnym. Oczywiście, ten porządek może zostać w mniejszym lub większym stopniu zakłócony poprzez stosowanie najróżniejszych opcjonalnych makroinstrukcji i dyrektyw, jednak sam czysty kod asemblerowy podchodzi pod tę definicję.