Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00049 006689 14488980 na godz. na dobę w sumie
Praktyczny kurs asemblera. Wydanie II - książka
Praktyczny kurs asemblera. Wydanie II - książka
Autor: Liczba stron: 424
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-2732-5 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> asembler - programowanie
Porównaj ceny (książka, ebook, audiobook).

Wejdź w świat programowania w języku asemblera

Uważasz, że możliwości języków programowania wysokiego poziomu nie pozwalają na napisanie programu, którego potrzebujesz? Chcesz stworzyć sterownik, program rezydentny, demo lub... wirusa? Interesuje Cię, co dzieje się w komputerze podczas wykonywania programu?

Wykorzystaj potencjał asemblera!

Programowanie w języku niskiego poziomu daje niemal nieograniczoną kontrolę nad sprzętem i działaniem aplikacji. Programy napisane w języku asemblera działają szybko, są niewielkie i zajmują mało pamięci. Są bardzo wydajne i otwierają dostęp do takich obszarów komputera, do których dostęp z poziomu C++ czy Visual Basica jest niemożliwy.

Książka 'Praktyczny kurs asemblera' wprowadzi Cię w świat programowania w tym języku. Dowiesz się, jak działa procesor, w jaki sposób komunikuje się z pamięcią i pozostałymi elementami komputera. Poznasz typy rozkazów procesora, tryby adresowania i zasady tworzenia programów w asemblerze. Lepiej poznasz swój komputer i dowiesz się, w jaki sposób zapamiętuje i przetwarza dane. Komputer przestanie być dla Ciebie 'czarną skrzynką' wykonującą w czarodziejski sposób Twoje polecenia.

Po przeczytaniu tej książki przestaniesz postrzegać asemblera jako zbiór magicznych zaklęć, zrozumiałych jedynie dla brodatych guru pamiętających jeszcze czasy komputerów zajmujących powierzchnię sali gimnastycznej. Napiszesz programy, których uruchomienie nie będzie wymagało od użytkownika posiadania superkomputera. Poznasz wszystkie, nawet najgłębiej ukryte, możliwości komputera.

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Praktyczny kurs asemblera. Wydanie II Autor: Eugeniusz Wróbel ISBN: 978-83-246-2732-5 Format: 158×235, stron: 424 • Dowiedz się, do czego może Ci się przydać asembler • Poznaj architekturę i sposób działania procesorów Intel • Naucz się pisać wydajne programy dla systemów DOS i Windows Zobacz, na co Cię stać z asemblerem! Programowanie w języku niskiego poziomu – choć czasem nieco uciążliwe – daje bardzo dużą swobodę w kwestii wykorzystania sprzętowych zasobów komputera i oferuje niemal nieograniczoną kontrolę nad sposobem działania programu. Aplikacje napisane za pomocą asemblera są bardzo szybkie i wydajne, a ponadto wymagają o wiele mniejszej ilości pamięci operacyjnej niż analogiczny kod, opracowany w językach wysokiego poziomu, takich jak C++, Java czy Visual Basic. Jeśli jesteś zainteresowany poszerzeniem swoich umiejętności programistycznych, z pewnością nadszedł czas, aby sięgnąć po asembler. Książka „Praktyczny kurs asemblera. Wydanie II” wprowadzi Cię w podstawowe zagadnienia związane z zastosowaniem języka niskiego poziomu do programowania komputerów opartych na architekturze x86-32 procesorów Intel (oraz AMD). Poznasz sposoby wykorzystania zasobów sprzętowych, zasadę działania procesora i listę jego instrukcji. Nauczysz się też, jak używać różnych trybów adresowania w celu optymalnego zarządzania zawartością rejestrów i pamięci. Dowiesz się, jak prawidłowo pisać, łączyć, kompilować i uruchamiać programy, a także poznasz praktyczne przykłady zastosowania asemblera. • Podstawowe informacje na temat asemblera i architektury x86-32 procesorów Intel (oraz AMD) • Przegląd narzędzi przydatnych przy tworzeniu i uruchamianiu kodu • Sposoby adresowania pamięci i korzystanie z rejestrów procesora • Lista instrukcji procesorów o architekturze x86-32 • Definiowanie i używanie zmiennych • Tworzenie podprogramów i makroinstrukcji • Korzystanie z funkcji systemu MS DOS i BIOS-a oraz windowsowych bibliotek typu API • Stosowanie asemblera do tworzenia programów uruchamianych pod systemem Windows • Tworzenie asemblerowych bibliotek typu dll z wykorzystaniem środowiska Microsoft Visual Studio • Przegląd metod optymalizacji kodu • Praktyczne przykłady programów wykorzystujących język asemblera Wykorzystaj w pełni potencjał asemblera! Idź do • Spis treści • Przykładowy rozdział • Skorowidz Katalog książek • Katalog online • Zamów drukowany katalog Twój koszyk • Dodaj do koszyka Cennik i informacje • Zamów informacje o nowościach • Zamów cennik Czytelnia • Fragmenty książek online Kontakt Helion SA ul. Kościuszki 1c 44-100 Gliwice tel. 32 230 98 63 e-mail: helion@helion.pl © Helion 1991–2011 Spis treĈci Ostatni wykäad Eugeniusza Wróbla ................................................. 7 Wprowadzenie do drugiego wydania ................................................ 9 Rozdziaä 1. Wprowadzenie ............................................................................. 11 Co to jest asembler? ........................................................................................ 11 1.1. Dlaczego programowaü w jĊzyku asemblera? ................................................ 14 1.2. 1.3. Dlaczego warto poznaü jĊzyk asemblera? ....................................................... 16 1.4. Wymagane umiejĊtnoĞci ................................................................................. 16 Konwencje stosowane w ksiąĪce .................................................................... 17 1.5. Rozdziaä 2. Pierwszy program w asemblerze ................................................... 21 „Hello, world!” pod kontrolą systemu operacyjnego MS DOS ....................... 22 „Hello, world!” pod kontrolą systemu operacyjnego Windows ...................... 25 2.1. 2.2. Rozdziaä 3. Architektura procesorów rodziny x86-32 widziana oczami programisty ........................................................ 33 Rejestry procesora 8086 .................................................................................. 34 3.1. 3.2. ZwiĊkszamy rozmiar rejestrów — od procesora 80386 do Intel Core i7 ........ 38 ZwiĊkszamy liczbĊ rejestrów — od procesora i486 do Intel Core i7 .............. 39 3.3. Segmentowa organizacja pamiĊci ................................................................... 44 3.4. Adresowanie argumentów ............................................................................... 48 3.5. Adresowanie argumentów w pamiĊci operacyjnej .......................................... 49 3.6. 3.7. Architektura x86-32e ...................................................................................... 52 Rozdziaä 4. Narzödzia ..................................................................................... 55 Asembler MASM ............................................................................................ 56 Program konsolidujący — linker .................................................................... 60 Programy uruchomieniowe ............................................................................. 62 Microsoft CodeView ....................................................................................... 64 Microsoft WinDbg .......................................................................................... 67 OllyDbg .......................................................................................................... 68 ĝrodowiska zintegrowane ............................................................................... 70 Microsoft Programmer’s WorkBench (PWB) ................................................. 70 ĝrodowisko zintegrowane MASM32 SDK ..................................................... 71 ĝrodowisko zintegrowane RadASM ............................................................... 74 WinAsm Studio ............................................................................................... 74 4.5. Microsoft Visual Studio .................................................................................. 75 4.1. 4.2. 4.3. 4.4. 4 Praktyczny kurs asemblera 6.1. 6.2. 6.3. 7.1. 7.2. 7.3. 7.4. 7.5. Rozdziaä 5. Lista instrukcji procesorów x86-32 ............................................... 81 Instrukcje ogólne — jednostki staáoprzecinkowej ........................................... 84 5.1. Koprocesor arytmetyczny — instrukcje jednostki zmiennoprzecinkowej ...... 87 5.2. Instrukcje rozszerzenia MMX ......................................................................... 90 5.3. 5.4. Instrukcje rozszerzenia SSE ............................................................................ 93 Instrukcje rozszerzenia SSE2 .......................................................................... 97 5.5. Instrukcje rozszerzenia SSE3, SSSE3 oraz SSE4 ......................................... 100 5.6. Instrukcje systemowe .................................................................................... 101 5.7. 5.8. Planowane rozszerzenie AVX ....................................................................... 102 Rozdziaä 6. Ogólna struktura programu asemblerowego ................................ 105 Uproszczone dyrektywy definiujące segmenty ............................................. 105 Peáne dyrektywy definiowania segmentów ................................................... 111 Dyrektywy pomocnicze ................................................................................ 114 Rozdziaä 7. Definiowanie i stosowanie zmiennych ......................................... 123 Zmienne caákowite ........................................................................................ 124 Zmienne zmiennoprzecinkowe ..................................................................... 127 Definiowanie tablic i áaĔcuchów ................................................................... 128 Struktury zmiennych ..................................................................................... 130 Dyrektywa definiująca pola bitowe ............................................................... 133 Rozdziaä 8. Podprogramy ............................................................................. 137 8.1. Stos ............................................................................................................... 137 8.2. Wywoáanie i organizacja prostych podprogramów ....................................... 140 8.3. Dyrektywa PROC – ENDP ........................................................................... 141 Parametry wywoáania podprogramu ............................................................. 146 8.4. 8.5. Zmienne lokalne ............................................................................................ 155 Rozdziaä 9. Makroinstrukcje oraz dyrektywy asemblacji warunkowej ............. 157 9.1. Makroinstrukcja definiowana ........................................................................ 157 Dyrektywa LOCAL ...................................................................................... 162 9.2. 9.3. Dyrektywy asemblacji warunkowej .............................................................. 163 9.4. Makroinstrukcje niedefiniowane ................................................................... 166 9.5. Makroinstrukcje tekstowe ............................................................................. 167 9.6. Makroinstrukcje operujące na áaĔcuchach (na tekstach) ............................... 168 Rozdziaä 10. Funkcje systemu MS DOS oraz BIOS .......................................... 171 10.1. Co ma prawo przerwaü wykonanie naszego programu? ............................... 171 10.2. Obsáuga klawiatury oraz funkcje grafiki na poziomie BIOS ......................... 174 10.3. Wywoáywanie podprogramów systemu operacyjnego MS DOS .................. 180 Rozdziaä 11. Programowanie w asemblerze w Ĉrodowisku Windows ................ 187 Systemowe programy biblioteczne ............................................................... 188 Pierwsze okno ............................................................................................... 191 Struktury programowe typu HLL .................................................................. 197 Program generatora okien Prostart ................................................................ 199 Rozdziaä 12. Wybrane zagadnienia optymalizacji programu .............................. 207 12.1. Kiedy i co powinniĞmy optymalizowaü w programie? ................................. 209 12.2. Optymalizujemy program przygotowany dla procesora x86-32 ................... 211 Modele pamiĊci — mieszanie kodów 16- i 32-bitowych .............................. 211 Wyrównywanie danych ................................................................................. 212 PamiĊü podrĊczna ......................................................................................... 213 Unikanie rozgaáĊzieĔ (skoków) ..................................................................... 215 OpóĨnienia wynikające z pierwszego wykonania oraz rozwijanie pĊtli ........ 216 OpóĨnienia związane z zapisywaniem i odczytywaniem .............................. 217 11.1. 11.2. 11.3. 11.4. Spis treĈci 5 12.3. Wspieramy proces optymalizacji za pomocą programu Vtune ..................... 218 12.4. Na ile róĪnych sposobów moĪemy zakodowaü kopiowanie tablic? .............. 219 Metoda 1.: Z wykorzystaniem instrukcji MOVSB ........................................ 221 Metoda 2.: Z wykorzystaniem instrukcji MOVSD ....................................... 221 Metoda 3.: Jawna pĊtla z instrukcjami MOV ................................................ 222 Metoda 4.: PĊtla z instrukcją MOV, rozwiniĊta ............................................ 222 Metoda 5.: PĊtla rozwiniĊta, grupowanie operacji odczytu i zapisu .............. 223 Metoda 6.: Wykorzystujemy rejestry MMX ................................................. 223 Metoda 7.: Modyfikujemy metodĊ 6., stosując instrukcje MOVNTQ i SFENCE ............................................................................................... 224 Metoda 8.: Na początku pĊtli z poprzedniej metody wprowadzamy instrukcjĊ pobrania wstĊpnego do pamiĊci podrĊcznej ........................... 225 Metoda 9.: Wykorzystujemy 128-bitowe rejestry rozszerzenia SSE ............. 225 Rozdziaä 13. Podziaä programu na moduäy i äñczenie moduäów zakodowanych w róĔnych jözykach programowania ..................... 227 13.1. Jak realizowaü poáączenia miĊdzymoduáowe? .............................................. 228 13.2. Mieszamy moduáy przygotowane w róĪnych jĊzykach ................................. 232 Rozdziaä 14. Tworzenie projektu asemblerowego w Ĉrodowisku Microsoft Visual Studio .............................................................. 239 14.1. Wstawki asemblerowe w programie uruchamianym w jĊzyku C++ ............. 239 14.2. Asemblerowa biblioteka dll w Ğrodowisku Microsoft Visual Studio ............ 245 Rozdziaä 15. Przykäadowe programy dla systemu operacyjnego MS DOS .......... 251 Pierwsze kroki w prostym trybie graficznym ................................................ 252 15.1. 15.2. Pozorujemy gáĊbiĊ ........................................................................................ 255 15.3. Generowanie fraktali ..................................................................................... 258 Rozdziaä 16. Przykäadowe programy dla systemu operacyjnego Windows ......... 265 16.1. Zegarek ......................................................................................................... 265 16.2. Wykorzystanie biblioteki OpenGL ............................................................... 270 16.3. Prosty edytor graficzny ................................................................................. 273 Rozdziaä 17. Biblioteki asemblerowe w Ĉrodowisku Microsoft Visual Studio .... 293 17.1. Tworzenie projektu asemblerowego dla Ğrodowiska Visual Studio 2008 ..... 293 17.2. Szyfrowanie .................................................................................................. 301 17.3. Edytor graficzny ............................................................................................ 307 17.4. Steganografia ................................................................................................ 312 Zaäñcznik 1. Interesujñce strony w internecie ................................................ 317 Zaäñcznik 2. Lista dyrektyw i pseudoinstrukcji jözyka MASM .......................... 319 Z2.1. Dyrektywy okreĞlające listĊ instrukcji procesora .......................................... 319 Z2.2. Organizacja segmentów ................................................................................ 321 Z2.3. Definiowanie staáych oraz dyrektywy związane z nazwami symbolicznymi .............................................................................................. 323 Z2.4. Definiowanie zmiennych .............................................................................. 324 Z2.5. Dyrektywy asemblacji warunkowej .............................................................. 326 Z2.6. Makroinstrukcje i dyrektywy z nimi związane .............................................. 327 Z2.7. Pseudoinstrukcje typu HLL ........................................................................... 329 Z2.8. Dyrektywy związane z podprogramami ........................................................ 329 Z2.9. Dyrektywy wpáywające na ksztaát listingu asemblacji .................................. 330 Z2.10. Poáączenia miĊdzymoduáowe ........................................................................ 332 Z2.11. Dyrektywy związane z diagnostyką procesu asemblacji ............................... 333 Z2.12. Inne dyrektywy i pseudoinstrukcje ............................................................... 334 6 Praktyczny kurs asemblera Zaäñcznik 3. Operatory stosowane w jözyku MASM ........................................ 337 Z3.1. Operatory stosowane w wyraĪeniach obliczanych w czasie asemblacji ........ 337 Z3.2. Operatory stosowane w wyraĪeniach obliczanych w czasie wykonywania programu ....................................................................................................... 341 Zaäñcznik 4. Symbole predefiniowane ............................................................. 343 Zaäñcznik 5. Przeglñd instrukcji procesora x86-32 .......................................... 347 Instrukcje ogólne (jednostki staáoprzecinkowej) .............................................347 Instrukcje jednostki zmiennoprzecinkowej (koprocesora arytmetycznego) ....354 Instrukcje rozszerzenia MMX ..........................................................................357 Instrukcje rozszerzenia SSE .............................................................................360 Instrukcje rozszerzenia SSE2 ...........................................................................363 Instrukcje rozszerzenia SSE3 ...........................................................................367 Instrukcje systemowe .......................................................................................368 Zaäñcznik 6. Opis wybranych przerwaþ systemu BIOS ..................................... 371 Z5.1. Z5.2. Z5.3. Z5.4. Z5.5. Z5.6. Z5.7. Z6.1. Funkcje obsáugi klawiatury wywoáywane przerwaniem programowym INT 16h ......................................................................................................... 371 Z6.2. Funkcje obsáugi karty graficznej wywoáywane przerwaniem programowym INT 10h ......................................................................................................... 373 Zaäñcznik 7. Wywoäania funkcji systemu operacyjnego MS DOS ...................... 379 Z7.1. Funkcje realizujące odczyt lub zapis znaku z ukáadu wejĞciowego lub wyjĞciowego ........................................................................................... 379 Z7.2. Funkcje operujące na katalogach .................................................................. 381 Z7.3. Operacje na dysku ......................................................................................... 381 Z7.4. Operacje na plikach (zbiorach) dyskowych .................................................. 383 Z7.5. Operacje na rekordach w pliku ..................................................................... 385 Z7.6. Zarządzanie pamiĊcią operacyjną ................................................................. 386 Z7.7. Funkcje systemowe ....................................................................................... 387 Z7.8. Sterowanie programem ................................................................................. 388 Z7.9. Funkcje związane z czasem i datą ................................................................. 389 Z7.10. Inne funkcje .................................................................................................. 390 Zaäñcznik 8. Opis wybranych funkcji API ........................................................ 391 Z8.1. CheckDlgButton ........................................................................................... 391 Z8.2. CloseHandle .................................................................................................. 392 Z8.3. CopyFile ....................................................................................................... 393 Z8.4. CreateFile ...................................................................................................... 394 Z8.5. CreateWindowEx .......................................................................................... 396 Z8.6. DeleteFile ...................................................................................................... 399 Z8.7. ExitProcess .................................................................................................... 399 Z8.8. GetFileSize .................................................................................................... 400 Z8.9. MessageBox .................................................................................................. 400 Z8.10. ShowWindow ................................................................................................ 403 Zaäñcznik 9. Tablica kodów ASCII oraz kody klawiszy ..................................... 405 Z9.1. Kody ASCII .................................................................................................. 405 Z9.2. Kody klawiszy .............................................................................................. 405 Zaäñcznik 10. FTP wydawnictwa ...................................................................... 411 Skorowidz .................................................................................. 413 Rozdziaä 3. Architektura procesorów rodziny x86-32 widziana oczami programisty Wszystkie instrukcje procesora1, takie jak np. operacje arytmetyczne czy logiczne, z jakich skáada siĊ program, wykonywane są na zmiennych w rejestrach procesora lub w pamiĊci operacyjnej. W dalszej czĊĞci tego rozdziaáu musimy zatem poznaü:  rejestry procesora dostĊpne programowo i podstawowe formaty danych związanych w tymi rejestrami,  organizacjĊ pamiĊci operacyjnej,  pojĊcie adresu logicznego, liniowego i rzeczywistego,  sposoby adresowania argumentów w pamiĊci operacyjnej,  tryby pracy procesora. KaĪdy kolejny procesor firmy Intel naleĪący do tzw. linii procesorów x86-32 byá tak rozbudowywany, aby oprogramowanie dziaáające na poprzednim, starszym modelu pro- cesora mogáo byü w dalszym ciągu uĪywane. Aby to byáo moĪliwe, w najnowszym proce- sorze Intel Core i7 moĪemy „zobaczyü” procesor 8086 i jego rejestry z charakterystyczną dla niego segmentową organizacją pamiĊci i sposobami adresowania argumentów. 1 W dalszej czĊĞci ksiąĪki 32-bitową architekturĊ procesorów firmy Intel nazywaü bĊdziemy konsekwentnie x86-32 dla podkreĞlenia, Īe wywodzi siĊ ona od pierwszego 16-bitowego procesora 8086. Firma Intel od pewnego czasu zrezygnowaáa z tej nazwy na rzecz IA-32. Do tej duĪej grupy procesorów zaliczamy wszystkie procesory rodziny Celeron, Pentium i Core. Z wyjątkiem podrozdziaáu 3.15 nie bĊdziemy zajmowaü siĊ w tej ksiąĪce 64-bitowym rozszerzeniem architektury procesorów Intel, oznaczanym jako x86-32e lub teĪ EM64T, a w przypadku procesorów firmy AMD — x86-64. 34 Praktyczny kurs asemblera Warto wspomnieü w tym miejscu, iĪ w procesorach linii x86-32 odszukaü moĪna pewien Ğlad jeszcze wczeĞniejszych procesorów: 8-bitowych 8080 oraz 8085, a nawet Ğlad pierw- szego mikroprocesora firmy Intel z 1969 roku, 4-bitowego procesora 4004. 3.1. Rejestry procesora 8086 Procesor 8086 to pierwszy procesor firmy Intel, w którym podstawowe rejestry dostĊpne programowo są 16-bitowe. Z niewielkim uproszczeniem moĪemy przyjąü, Īe wspóá- czesny procesor o architekturze x86-32 po wáączeniu komputera do zasilania widziany jest przez programistĊ jako bardzo szybki procesor 8086. BĊdziemy mówili, Īe procesor pracuje wtedy w trybie adresacji rzeczywistej bądĨ w trybie 16-bitowym (choü pro- gramowo dostĊpne bĊdą juĪ rejestry 32-bitowe, wprowadzone w procesorze 80386). Programy uruchamiane pod kontrolą systemu operacyjnego MS DOS wykorzystywaü bĊdą ten wáaĞnie tryb. Instrukcje procesora 8086 stanowią podzbiór zbioru instrukcji wspóáczesnego procesora Intel Core i7. Mogą one operowaü na oĞmiu podstawowych rejestrach (rysunek 3.1) oraz na argumentach w pamiĊci operacyjnej. Rysunek 3.1. Podstawowe rejestry procesora 8086 Nazwy rejestrów przedstawiono na rysunku wielkimi literami, jednak w programie dla wygody najczĊĞciej zapisywaü bĊdziemy je literami maáymi. JĊzyk asemblera dopusz- cza w tym zakresie peáną dowolnoĞü. Rejestry AX, BX, CX, DX, SI, DI, BP oraz SP w czasie wykonywania programu mogą zawieraü odpowiednio:  argumenty dla wykonywanych w programie operacji arytmetycznych oraz logicznych,  argumenty sáuĪące do obliczania adresu w pamiĊci operacyjnej,  wskaĨniki do pamiĊci operacyjnej. NiezaleĪnie od tego, Īe z wyjątkiem rejestru SP wszystkie pozostaáe bĊdziemy mogli wykorzystywaü do róĪnych z wymienionych powyĪej celów, kaĪdy z nich ma takĪe swoją specyficzną funkcjĊ, która związana jest z jego nazwą. WyjaĞnia to poniĪsze zestawienie: Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 35 AX  gáówny rejestr jednostki staáoprzecinkowej procesora, sáuĪy jako akumulator dla argumentów instrukcji procesora oraz zapamiĊtania wyników, BX  rejestr bazowy, wskaĨnik do danych w pamiĊci (w segmencie danych2), CX  licznik w operacjach na áaĔcuchach oraz w pĊtlach programowych, DX  rejestr danych, rejestr adresowy ukáadów wejĞcia-wyjĞcia, SI  rejestr indeksowy, wskaĨnik do danych w segmencie danych; w operacjach na áaĔcuchach wskaĨnik dla áaĔcucha Ĩródáowego, DI  rejestr indeksowy, wskaĨnik do danych; w operacjach na áaĔcuchach wskaĨnik do áaĔcucha przeznaczenia, BP  rejestr bazowy, wskaĨnik do danych w segmencie stosu, SP  wskaĨnik szczytu stosu. W rejestrach AX, BX, CX, DX moĪemy niezaleĪnie adresowaü ich máodsze i starsze bajty, odpowiednio uĪywając nazw: AH, AL, BH, BL, CH, CL, DH i DL. Przypomnijmy sobie, Īe w naszym „pierwszym programie”, wyĞwietlającym na ekranie napis „Hello, world!”, wykorzystywaliĞmy dwa spoĞród wymienionych wyĪej rejestrów: DX oraz AH. Przez te rejestry przekazywaliĞmy parametry do podprogramu syste- mowego. Listą instrukcji procesora zajmowaü siĊ bĊdziemy w rozdziale 5., jednak juĪ teraz poka- Īemy przykáadowe instrukcje (rozkazy) wykorzystujące poznane rejestry: mov ax, bx ; skopiuj zawartoĞü rejestru BX do rejestru AX add ah, cl ; dodaj binarnie zawartoĞü rejestru CL do rejestru AH, ; wynik umieĞü w rejestrze AH neg bx ; negacja zawartoĞci rejestru BX (operacja na bitach) cmp di, si ; porównaj zawartoĞci rejestrów DI oraz SI Wymieniü musimy jeszcze dwa inne rejestry procesora 8086: wskaĨnik instrukcji IP oraz rejestr znaczników FLAGS. Rejestry te pokazane są na rysunku 3.2. Rysunek 3.2. Rejestry FLAGS oraz IP procesora 8086 Rejestr IP wskazywaü bĊdzie adres w segmencie kodu, z którego kolejno pobierane bĊdą instrukcje programu do wykonania. Po pobraniu instrukcji jego zawartoĞü powiĊk- szana bĊdzie o taką liczbĊ bajtów, z ilu skáada siĊ dana instrukcja. W przypadku instrukcji 2 O segmentowej organizacji pamiĊci bĊdziemy mówiü w dalszych czĊĞciach tego rozdziaáu. 36 Praktyczny kurs asemblera skoku bądĨ wywoáania podprogramu, czyli przeniesienia sterowania w inne miejsce programu, do rejestru IP zapisywany bĊdzie adres, pod którym zaczynają siĊ instrukcje tego fragmentu programu (bądĨ podprogramu), jakie mają byü wykonywane. Szczególne znaczenie w procesorze ma rejestr jednobitowych znaczników FLAGS. WyróĪniamy wĞród nich 6 znaczników stanu oraz 3 znaczniki sterujące. Znaczniki stanu informują o pewnych cechach otrzymanego wyniku po wykonaniu operacji arytmetycz- nej bądĨ logicznej. Ilustruje to tabela 3.1. Tabela 3.1. Znaczniki stanu w rejestrze FLAGS Symbol znacznika Nazwa znacznika CF znacznik przeniesienia (ang. carry flag) PF AF ZF SF OF znacznik parzystoĞci (ang. parity flag) znacznik przeniesienia pomocniczego (ang. auxiliary flag) znacznik zera (ang. zero flag) znacznik znaku (ang. sign flag) znacznik przepeánienia (ang. overflow flag) Jak siö zachowuje po operacji arytmetycznej bñdĒ logicznej Przyjmuje wartoĞü 1, gdy w wyniku wykonanej operacji nastąpiáo przeniesienie (np. przy dodawaniu) z bitu najstarszego na zewnątrz lub teĪ (np. przy odejmowaniu) nastąpiáa poĪyczka z zewnątrz do bitu najstarszego. W przeciwnym razie znacznik jest zerowany. Ustawiany jest na wartoĞü 1 wtedy, gdy w wyniku zrealizowanej operacji liczba bitów o wartoĞci 1 w máodszym bajcie wyniku jest parzysta. Gdy jest nieparzysta, znacznik jest zerowany. Przyjmuje wartoĞü 1, gdy nastąpiáo przeniesienie z bitu 3 na 4 lub poĪyczka z bitu 4 na 3. W przeciwnym razie wskaĨnik jest zerowany. WskaĨnik AF wykorzystywany jest przy operacjach na liczbach BCD. Przyjmuje wartoĞü 1 wtedy, gdy wynik operacji jest równy zero, i jest zerowany w przeciwnym razie. Przyjmuje wartoĞü 1, gdy najbardziej znaczący bit (bit znaku) w otrzymanym wyniku jest równy 1, i jest zerowany w przeciwnym razie. Stan znacznika SF jest zatem zgodny z bitem znaku. Przyjmuje wartoĞü 1, gdy przy realizowaniu okreĞlonej operacji wystąpiáo przeniesienie na bit znaku lub teĪ z tego bitu pobrana zostaáa poĪyczka, ale nie wystąpiáo przeniesienie (lub poĪyczka) z bitu znaku (tzn. CF=0) W przeciwnym razie znacznik jest zerowany. Stan znacznika OF jest istotny w czasie operacji na liczbach ze znakiem. Przykäad 1010 1110 + 0111 0100 1 0010 0010 CF=1 0010 1100 + 1011 0001 1101 1101 PF=1 0010 1110 + 0110 0100 1001 0010 AF=1 1111 1111 + 0000 0001 0000 0000 ZF=1 0110 0000 + 0100 0001 1010 0001 SF=1 0110 1010 + 0101 1001 1100 0011 OF=1 W zaleĪnoĞci od stanu pojedynczych znaczników lub ich logicznej kombinacji moĪna dziĊki zastosowaniu wáaĞciwych instrukcji skoków zmieniü przebieg realizowanego programu. Analizując ustawienia znaczników stanu, warto pamiĊtaü, Īe procesor nie Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 37 rozróĪnia, czy liczba traktowana jest przez nas w programie jako liczba ze znakiem, czy teĪ bez znaku. Klasycznym przykáadem ilustrującym, w jaki sposób procesor wyko- rzystuje znacznik zera ZF, moĪe byü nastĊpująca sekwencja instrukcji: ; porównaj zawartoĞü rejestrów – ustaw znaczniki w rej. FLAGS ; skocz do etykiety sa_rowne, jeĞli znacznik zera zostaá ; ustawiony ; kontynuuj w przeciwnym razie cmp al, bh jz sa_rowne ... Wykonanie instrukcji cmp sprowadza siĊ do wykonania operacji odejmowania. Wynik odejmowania nie zostaje zapamiĊtany, a jedynie ustawione zostają znaczniki, w tym znacznik zera ZF. Rozkaz skoku warunkowego jz (ang. jump if zero flag) bada stan tego znacznika i jeĞli stwierdzi, Īe jest równy 1 (co oznacza, Īe w wyniku odejmowania wynik byá równy zero, czyli porównywane rejestry zawieraáy te same wartoĞci), przenie- sie sterowanie do etykiety (adresu symbolicznego) o nazwie sa_rowne. W przeciwnym razie skok nie jest wykonywany i procesor przechodzi do realizacji kolejnej instrukcji. Inny rodzaj znaczników w rejestrze FLAGS to znaczniki sterujące. Mogą byü ustawiane bądĨ zerowane programowo w celu wymuszenia odpowiedniego sposobu pracy pro- cesora. Ilustruje je tabela 3.2. Tabela 3.2. Znaczniki sterujące w rejestrze FLAGS Nazwa znacznika Znaczenie znacznika Symbol znacznika TF znacznik pracy krokowej (ang. trap flag) IF DF znacznik zezwolenia na przerwanie (ang. interrupt flag) znacznik kierunku (ang. direction flag) Stan równy 1 powoduje wprowadzenie procesora w tryb pracy (ang. single step mode) umoĪliwiający wygenerowanie przerwania (ang. single step interrupt) i przejĞcie do specjalnych procedur obsáugi (np. programów uruchomieniowych) po kaĪdym wykonanym rozkazie. Wyzerowanie znacznika TF powoduje powrót procesora do normalnej pracy. Ustawiony w stan 1 powoduje odblokowanie systemu przerwaĔ procesora. ZewnĊtrzne przerwania maskowane mogą przerwaü realizacjĊ wykonywanego aktualnie programu. Wyzerowanie znacznika powoduje, Īe przerwania te są przez procesor ignorowane. Wykorzystywany jest przy wykonywaniu operacji na áaĔcuchach (tablicach). JeĪeli ma wartoĞü 0, przetwarzanie áaĔcuchów odbywa siĊ z inkrementacją adresów, jeĪeli zaĞ jest ustawiony — adresy maleją. Procesory x86-32, a zatem takĔe wspóäczesne procesory serii Intel Core, po wäñ- czeniu do zasilania pracujñ w trybie adresacji rzeczywistej. Na tym etapie rozwa- Ĕaþ moĔemy, upraszczajñc, przyjñè, Ĕe dla programisty jest to wtedy bardzo szybki procesor 8086. W tym trybie ma on do dyspozycji 8 rejestrów 16-bitowych, z których kaĔdy moĔe zawieraè argument wykonywanych instrukcji lub teĔ moĔe säuĔyè do obliczenia adresu argumentu w pamiöci operacyjnej. 38 Praktyczny kurs asemblera 3.2. Zwiökszamy rozmiar rejestrów — od procesora 80386 do Intel Core i73 W procesorze 80386 w miejsce poznanych poprzednio rejestrów 16-bitowych wpro- wadzono rejestry 32-bitowe. I tak juĪ pozostaáo — aĪ do wspóáczesnych procesorów o architekturze x86-32 (pracujących w trybie 32-bitowym). Procesory te posiadają szereg innych, dodatkowych rejestrów, które poznamy w dalszej czĊĞci rozdziaáu. Ukáad pod- stawowych oĞmiu rejestrów i ich przeznaczenie praktycznie siĊ nie zmieniáy, co pokazuje rysunek 3.3. Rysunek 3.3. Rejestry podstawowe procesora 80386 i nowszych Jak widaü na tym rysunku, wszystkie rejestry zostaáy powiĊkszone do 32 bitów, zaĞ w nazwie pojawiáa siĊ na pierwszym miejscu litera „E”, od angielskiego sáowa expand — poszerzenie, powiĊkszenie. W programie wykorzystywaü moĪemy zarówno 32-bitowe rejestry: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP, jak i mapowane na nich, znane nam juĪ rejestry 16-bitowe: AX, BX, CX, DX, SI, DI, BP, SP oraz, odpo- wiednio, oĞmiobitowe: AH, AL, BH, BL, CH, CL, DH, CL. Rola rejestrów 32-bitowych jest generalnie zgodna z opisaną wczeĞniej rolą ich odpowiedników 16-bitowych. DziĊki temu zachowana zostaáa zgodnoĞü programowa „w dóá”, tzn. programy przygotowane dla starszych procesorów mogą byü wykonywane na procesorach nowszych. Począwszy od procesora 80386, konsekwentnie mamy teĪ do dyspozycji 32-bitowy rejestr wskaĨnika rozkazów EIP, a takĪe 32-bitowy rejestr znaczników EFLAGS. W reje- strze EFLAGS oprócz znanych nam z procesora 8086 znaczników stanu oraz znaczników sterujących pojawiáa siĊ nowa grupa znaczników: znaczniki systemowe. Są one zwią- zane z pracą procesora w trybie adresacji wirtualnej z ochroną i nie mogą byü uĪywane w programie uĪytkowym. Z tego teĪ wzglĊdu nie bĊdziemy siĊ nimi zajmowaü w tej ksiąĪce. Podstawowe typy danych, jakimi operowaü bĊdziemy, wykorzystując pokazane na rysunku 3.3 rejestry procesora, pokazuje rysunek 3.4. PokaĪmy teraz przykáadowe instrukcje procesora, wykorzystujące pokazane na rysunku 3.3 rejestry procesora 80386: 3 W architekturze x86-32. Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 39 Rysunek 3.4. Podstawowe typy danych and eax, esi ; iloczyn logiczny bitów rejestrów EAX i ESI cwde ; (argument niejawny) konwersja liczby ze znakiem ; w rejestrze AX do rejestru EAX (czyli z liczby ; 16-bitowej robimy 32-bitową) cmp bp, bx ; porównanie zawartoĞci rejestrów BP i BX ; (ustawia znaczniki w EFLAGS) mov edi, esi ; skopiowanie zawartoĞci rejestru indeksowego ESI do EDI sub ecx, 8 ; odjĊcie od zawartoĞci rejestru ECX liczby 8 3.3. Zwiökszamy liczbö rejestrów — od procesora i4864 do Intel Core i75 Wykonywanie záoĪonych obliczeĔ na liczbach zmiennoprzecinkowych przy wykorzy- staniu dotychczas poznanych przez nas rejestrów jest uciąĪliwe i maáo wydajne. Dla- tego teĪ równolegle do procesora 8086 powstaá koprocesor arytmetyczny 8087 (jako oddzielny ukáad scalony), a póĨniej odpowiednio dla kolejnych procesorów 80286 i 80386 koprocesory: 80287 i 80387. Koprocesor arytmetyczny posiada 80-bitowe rejestry oraz listĊ instrukcji pozwalającą na stosunkowo proste wykonywanie nawet bardzo záoĪonych operacji matematycznych na liczbach zmiennoprzecinkowych. Dla progra- misty procesor gáówny oraz koprocesor arytmetyczny tworzyáy od początku jak gdyby jeden procesor o powiĊkszonych moĪliwoĞciach. W programie w identyczny sposób 4 Wedáug wczeĞniejszego nazewnictwa firmy Intel — 80486. 5 W architekturze x86-32. 40 Praktyczny kurs asemblera umieszczaü moĪna instrukcje wykonywane przez kaĪdy z tych procesorów. Począw- szy od procesora i486, koprocesor arytmetyczny wáączony zostaá do procesora gáów- nego, przy zachowaniu wszystkich swoich funkcji. W procesorach o architekturze x86-32 wystĊpuje w postaci tzw. jednostki zmiennoprzecinkowej6 — w odróĪnieniu od jednostki staáoprzecinkowej, bazującej na omówionych wczeĞniej rejestrach 32-bitowych. Rejestry jednostki zmiennoprzecinkowej (koprocesora arytmetycznego) dostĊpne pro- gramowo przedstawia rysunek 3.5. Rysunek 3.5. 80-bitowe rejestry koprocesora arytmetycznego (z zaznaczeniem pól zajmowanych przez liczbĊ zmiennoprzecinkową) Instrukcje operujące na tych rejestrach traktują je jako stos oĞmiu rejestrów, przy czym rejestr wskazywany przez 3-bitowy wskaĨnik jako szczyt stosu nazywaü bĊdziemy ST(0) lub po prostu ST. Kolejne rejestry to odpowiednio: ST(1), ST(2) itd. aĪ do ST(7). Pokazuje to rysunek 3.6. Rysunek 3.6. Stosowa organizacja rejestrów koprocesora arytmetycznego Zapis do rejestru ST(0), którym w danym momencie bĊdzie np. rejestr R3, wiązaü siĊ bĊdzie z wczeĞniejszym odjĊciem od trzybitowego wskaĨnika stosu jedynki i tym samym operacja zapisu wykonana zostanie do R2. Rejestr R3, bĊdący poprzednio szczytem stosu, stanie siĊ rejestrem ST(1). Do rejestrów ST(i) dane zapisywane bĊdą w formacie: znak, wykáadnik, mantysa — tak jak pokazują to rysunki 3.4 i 3.5. PoniĪej pokaĪemy kilka przykáadowych instrukcji procesora operujących na tych rejestrach: fldpi ; zaáadowanie na szczyt stosu do rejestru ST(0) ; liczby staáej „pi” fld zmienna ; zaáadowanie na szczyt stosu do rejestru ST(0) ; zmiennej z pamiĊci 6 Informatycy — szczególnie ci pamiĊtający czasy procesorów 8086, 80286 i 80386, jak i koprocesorów arytmetycznych 8087, 80287 i 80387 — w dalszym ciągu operują pojĊciem koprocesor arytmetyczny, mimo iĪ jest on w tej chwili integralną czĊĞcią procesora o architekturze x86-32. Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 41 fsin ; obliczenie funkcji sinus z liczby ; umieszczonej w ST(0) fsub ST(0), ST(3) ; operacja na liczbach zmiennoprzecinkowych: ; ST(0)ÅST(0)-ST(3) fxch ST(5) ; zamiana zawartoĞci rejestrów ST(0) i ST(5) Wykonywanie operacji na liczbach zmiennoprzecinkowych nie jest — niestety — sprawą prostą. Musimy pamiĊtaü o uáomnoĞci kaĪdej cyfrowej maszyny matematycznej w zakresie przedstawiania osi liczbowej, moĪliwej do osiągniĊcia dokáadnoĞci obliczeĔ czy wreszcie koniecznoĞci operowania takimi podstawowymi w matematyce pojĊciami, jak np. nieskoĔczonoĞü. Kolejne rejestry udostĊpnione zostaáy programistom w procesorze Pentium MMX. Byá to przejĞciowy model procesora produkowany przez krótki czas, dlatego mówi siĊ raczej, Īe rozszerzenie procesora o nazwie MMX pojawiáo siĊ w Pentium II. KoniecznoĞü zwiĊkszania mocy obliczeniowej wymaganej w coraz bardziej popularnych zastosowa- niach multimedialnych spowodowaáa siĊgniĊcie do tzw. technologii SIMD (ang. Single Instruction Multiple Data). W technologii tej pojedyncza instrukcja procesora wykony- wana jest równolegle na kilku danych. Rejestry oraz wprowadzone wraz z tzw. rozsze- rzeniem MMX typy danych pozwalające wykonywaü tego typu operacje w procesorze Pentium II (i oczywiĞcie takĪe nowszych) przedstawia rysunek 3.7. Rysunek 3.7. Rejestry MMX oraz typy danych KaĪdy z oĞmiu 64-bitowych rejestrów moĪe zawieraü:  jedną daną 64-bitową,  dwie dane 32-bitowe (ang. Packed Doubleword Integers),  cztery dane 16-bitowe (ang. Packed Word Integers),  8 danych bajtowych (ang. Packed Byte Integers), na których równoczeĞnie wykonywaü moĪemy okreĞlone operacje, w szczególnoĞci arytmetyczne i logiczne na liczbach caákowitych. Przykáady wykorzystania rejestrów MMX w programie asemblerowym pokazane bĊdą w dalszych rozdziaáach, teraz przed- stawimy jedynie kilka przykáadowych instrukcji procesora wykorzystujących te rejestry. pxor mm1, mm2 ; wykonaj operacjĊ logiczną XOR na bitach ; rejestrów MM1 i MM2 psslq mm1, 3 ; przesuĔ logicznie zawartoĞü (caáego) ; rejestru MM1 w lewo o 3 bity 42 Praktyczny kurs asemblera paddb mm2, mm3 ; dodaj odpowiadające sobie bajty rejestrów MM2 i MM3 paddw mm2, mm3 ; dodaj odpowiadające sobie sáowa rejestrów MM2 i MM3 W procesorze Pentium III wprowadzono kolejnych osiem rejestrów, tym razem 128-bito- wych, które stanowią podstawowe zasoby rozszerzenia procesora o architekturze x86-32 o nazwie SSE (ang. the Streaming SIMD Extensions). W procesorze Pentium 4 nie przy- byáo juĪ Īadnych dostĊpnych programowo rejestrów, jedynie rozbudowana zostaáa lista instrukcji. Rozszerzenie procesora Pentium 4 nazwano w związku z tym SSE2. Rejestry rozszerzeĔ SSE i SSE2 nazywamy XMM (rysunek 3.8). Podobnie jak opisane wcze- Ğniej rejestry MMX, pracują one w technologii SIMD. O ile jednak w poprzednich rejestrach mogliĞmy przetwarzaü równolegle kilka danych bĊdących liczbami caáko- witymi, o tyle teraz operacje bĊdą moĪliwe takĪe na liczbach zmiennoprzecinkowych. W pewnym uproszczeniu moĪna powiedzieü, Īe rozszerzenie SSE/SSE2 áączy w sobie moĪliwoĞci koprocesora arytmetycznego (przetwarzanie liczb zmiennoprzecinkowych) oraz MMX (przetwarzanie typu SIMD). Rozszerzenia SSE/SSE2 wprowadzone zostaáy w celu zwiĊkszenia szybkoĞci przetwarzania w takich zastosowaniach, jak grafika 2D i 3D, przetwarzanie obrazów, animacja, rozpoznawanie mowy, obsáuga wideokonferen- cji itp. W lutym 2004 roku firma Intel wprowadziáa na rynek wersjĊ procesora Pen- tium 4 z jądrem o nazwie Prescott. W procesorze tym wprowadzono rozszerzenie o nazwie SSE3. Lista instrukcji kolejny raz zostaáa powiĊkszona, jednak nie zmieniáa siĊ liczba dostĊpnych programowo rejestrów. W nastĊpnych wersjach procesorów o archi- tekturze x86-32 wprowadzono kolejne rozszerzenia listy rozkazów (SSSE3, SSE4), jednak liczba oraz wielkoĞü rejestrów dostĊpnych programowo w trybie pracy 32-bitowej nie ulegáy7 zmianie. Rysunek 3.8. Rejestry XMM rozszerzenia SSE/SSE2/SSE3/SSE4 W procesorach o architekturze x86-32 w kaĪdym ze 128-bitowych rejestrów moĪemy równolegle przetwarzaü (rysunek 3.9):  cztery 32-bitowe liczby zmiennoprzecinkowe pojedynczej precyzji8,  dwie 64-bitowe liczby zmiennoprzecinkowe podwójnej precyzji,  szesnaĞcie bajtów9 traktowanych jako liczby staáoprzecinkowe, 7 W chwili, gdy pisane są te sáowa, firma Intel wprowadziáa procesory Core i7, i5 oraz i3. W trybie 32-bitowym liczba rejestrów dostĊpnych programowo nie zostaáa zmieniona w stosunku do procesora Pentium III. 8 W procesorze Pentium III w 128-bitowych rejestrach XMM instrukcje obsáugują jedynie ten format danych. Pozostaáe formaty dostĊpne są w procesorze Pentium 4 oraz nowszych. 9 Ten i kolejne wymienione tutaj formaty staáoprzecinkowe są rozszerzeniem technologii MMX na rejestry XMM. Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 43 Rozszerzenie SSE w procesorze Pentium III Rozszerzenie SSE2 w procesorze Pentium 4 Rysunek 3.9. Typy danych w rejestrach XMM  osiem sáów (liczby staáoprzecinkowe),  cztery podwójne sáowa (liczby staáoprzecinkowe),  dwa poczwórne sáowa (liczby staáoprzecinkowe).  Wiemy juĪ, jakimi rejestrami moĪemy posáugiwaü siĊ w procesorze o architekturze x86-32, pisząc program w jĊzyku asemblera. Spójrzmy jeszcze na rysunek 3.10, który w uproszczony sposób pokazuje wszystkie rejestry, jakie bĊdziemy mieli do dyspozycji przy pisaniu programów uĪytkowych. NaleĪy równieĪ zaznaczyü, Īe 64-bitowe rejestry MMX w rzeczywistoĞci są mapowane na rejestrach koprocesora arytmetycznego ST(i), co w konsekwencji wymaga rozdzielenia w programie operacji wykonywanych na tych dwóch zbiorach rejestrów. Rysunek 3.10. Rejestry procesora x86-32 44 Praktyczny kurs asemblera Nie sñ to wszystkie dostöpne programowo rejestry procesora. Pewna liczba reje- strów zwiñzana jest z segmentowñ organizacjñ pamiöci, inne z kolei peäniñ istotnñ rolö przy organizowaniu pracy procesora w trybie adresacji wirtualnej z ochronñ. Niektóre z tych rejestrów poznamy, omawiajñc sposoby adresowania argumentów w pamiöci operacyjnej. Rejestry MMX sñ mapowane na rejestrach koprocesora ST(i), w zwiñzku z tym w pro- gramie nie moĔemy równoczeĈnie wykorzystywaè obu tych zbiorów rejestrów. Poczñw- szy od procesora Pentium 4, jest to juĔ mniejszy problem, poniewaĔ wszystkie operacje typu MMX moĔemy wykonywaè takĔe na rejestrach XMM. Jest to korzystne takĔe ze wzglödu na ich dwa razy wiökszy rozmiar w stosunku do rejestrów MMX. 3.4. Segmentowa organizacja pamiöci Dane przetwarzane w programie mogą znajdowaü siĊ bądĨ w omówionych juĪ rejestrach procesora, bądĨ teĪ w pamiĊci operacyjnej. Poznamy teraz sposób adresowania danych w pamiĊci. PamiĊü operacyjna ma organizacjĊ bajtową, co oznacza, Īe kaĪdy bajt w pamiĊci ma swój wáasny fizyczny adres. Maksymalna wielkoĞü pamiĊci operacyjnej, czyli liczba bajtów, jakie procesor moĪe zaadresowaü, zaleĪy od wielkoĞci magistrali adresowej. Dla kolejnych procesorów x86 przedstawia to tabela 3.3. Tabela 3.3. WielkoĞü pamiĊci operacyjnej w róĪnych procesorach firmy Intel WielkoĈè magistrali adresowej 20 bitów 24 bity 32 bity Maksymalna wielkoĈè pamiöci operacyjnej 1 MB 16 MB 4 GB WielkoĈè offsetu 16 bitów 16 bitów 32 bity Maksymalna wielkoĈè segmentu w pamiöci 64 kB 64 kB 4 GB 36 bitów 64 GB 32 bity 4 GB 40 bitów 1 TB 32 bity 4 GB Procesor 8086 80286 Począwszy od procesora 80386 do Pentium wáącznie Począwszy od procesora Pentium PRO do Pentium 4 Począwszy od Pentium 4 EE (Prescott) W programie nie bĊdziemy siĊ jednak posáugiwaü adresem fizycznym, tylko adresem logicznym. Fizyczna pamiĊü operacyjna umownie podzielona zostanie na pewne spójne fragmenty, zwane segmentami. KaĪdy bajt w pamiĊci bĊdziemy adresowaü poprzez adres logiczny skáadający siĊ z dwóch czĊĞci:  z adresu początku segmentu,  z adresu wzglĊdem początku segmentu, który nazywaü bĊdziemy offsetem. Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 45 WielkoĞü offsetu związana jest wprost z rozmiarem dostĊpnych w procesorze rejestrów ogólnego przeznaczenia, które — jak za chwilĊ pokaĪemy — bĊdą mogáy uczestniczyü w jego obliczaniu. I tak w procesorze 8086, a wiĊc takĪe w procesorach x86-32 pracują- cych w trybie adresacji rzeczywistej, offset ma 16 bitów, z czego wynika maksymalna wielkoĞü segmentu wynosząca 64 kilobajty. Począwszy od procesora 80386 pracującego w trybie adresacji wirtualnej, offset ma 32 bity, zaĞ maksymalna wielkoĞü segmentu to 4 gigabajty. Do okreĞlenia adresu początku segmentu sáuĪą rejestry procesora, zwane rejestrami segmentowymi. Procesor 8086 ma je cztery, zaĞ w procesorze 80386 i dalszych mamy do dyspozycji 6 takich rejestrów. WielkoĞü rejestrów segmentowych wynosi 16 bitów (rysunek 3.11), co powoduje, Īe ich zawartoĞü nie moĪe byü wprost fizycznym adresem początku segmentu. Wymagaáoby to bowiem odpowiednio wiĊkszych rejestrów: dla procesora 8086 rejestru 20-bitowego, zaĞ dla wspóáczesnych procesorów x86-32 — rejestru 40-bitowego lub, dla niektórych, 52-bitowego. Rysunek 3.11. Rejestry segmentowe procesora Pentium 4 Adres logiczny zapisywaü bĊdziemy, podając obie jego czĊĞci oddzielone dwukrop- kiem, np.: 1000:0000 3af8:076b DS:2ab7 ES:DI CS:IP Jak widaü, w wyraĪeniu okreĞlającym adres logiczny mogą wystąpiü konkretne liczby (na ogóá w kodzie szesnastkowym) bądĨ nazwy rejestrów, które zawierają odpowiednią wartoĞü segmentu lub offsetu. Warto zwróciü uwagĊ na adres logiczny CS:IP, który okreĞla, skąd pobierane bĊdą do wykonania kolejne instrukcje programu. Jak juĪ wiemy, w procesorze 8086 (lub inaczej: dla procesora x86-32 w trybie adre- sowania rzeczywistego) dla okreĞlenia fizycznego adresu początku segmentu potrzeba 20 bitów (porównaj tabelĊ 3.3). Rejestr segmentowy zawieraü bĊdzie w takim przy- padku 16 starszych bitów tego 20-bitowego adresu. Brakujące cztery najmáodsze bity bĊdą miaáy zawsze wartoĞü zero. Tak wiĊc adres początku segmentu w procesorze 46 Praktyczny kurs asemblera 8086 zawsze musi byü podzielny przez 16. Warto wiedzieü, wedáug jakiego algorytmu procesor 8086 przelicza adres logiczny uĪywany w programie na adres fizyczny. Ilustruje to prosty przykáad przeliczony dla adresu logicznego 2a87:1005. segment 2a87 0010 1010 1000 0111 offset + 100a 0001 0000 0000 1010 adres fizyczny 2b87a 0010 1011 1000 0111 1010 Segmentową organizacjĊ pamiĊci operacyjnej ilustruje schematycznie rysunek 3.12. W programie moĪemy zdefiniowaü wiele róĪnych segmentów, lecz w danym momencie dostĊp bĊdziemy mieli jedynie do szeĞciu, wskazywanych przez zawartoĞü poszczegól- nych rejestrów segmentowych. Segmenty w programie mogą siĊ nakáadaü na siebie w pamiĊci, mogą byü uáoĪone jeden po drugim lub teĪ miĊdzy poszczególnymi segmen- tami mogą wystĊpowaü przerwy. Dla najprostszego maáego programu musimy zdefi- niowaü po jednym segmencie z programem, danymi oraz stosem. Tak wáaĞnie zrobiliĞmy w naszym pierwszym programie „Hello, world!” w rozdziale 2., wybierając model pamiĊci SMALL. Rysunek 3.12. Segmentowa organizacja pamiĊci operacyjnej KaĪdy z rejestrów segmentowych związany jest z segmentem o ĞciĞle okreĞlonej roli: CS — wskazuje segment z programem (w skrócie segment kodu programu albo — jeszcze krócej — segment kodu), DS — wskazuje segment z danymi; wiĊkszoĞü operacji na danych bĊdzie standardowo związana z tym segmentem, SS — wskazuje segment stosu, ES, FS, GS — wskazują dodatkowe segmenty danych. Warto zauwaĪyü, Īe w trybie adresacji rzeczywistej ten sam bajt w pamiĊci moĪemy zaadresowaü róĪnymi adresami logicznymi. WystĊpuje tutaj redundancja wynikająca z tego, Īe do zaadresowania przestrzeni jednomegabajtowej uĪywamy aĪ 32 bitów adresu logicznego o postaci segment:offset. Przykáad ilustrujący to zagadnienie pokazany jest na rysunku 3.13. Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 47 Rysunek 3.13. RóĪne adresy logiczne wskazują ten sam adres fizyczny 135a1h w pamiĊci operacyjnej W przypadku procesorów x86-32 pracujących w trybie adresacji wirtualnej z ochroną przeliczanie zawartoĞci 16-bitowego rejestru segmentowego, zwanego w tym trybie selektorem, na odpowiadający mu adres początku segmentu jest znacznie bardziej záo- Īone. PoniewaĪ wymagaáoby to bardzo obszernego i drobiazgowego opisu, a przeli- czenie adresu jest procesem niewidocznym dla programu uĪytkowego, zagadnienie to nie bĊdzie tutaj przedstawione10. Programowanie w tym trybie pod kontrolą systemu Windows pozwala zapomnieü o segmentowej organizacji pamiĊci i operowaü jedynie 32-bitowym offsetem, który traktowany jest jako adres liniowy w przestrzeni 4-gigabaj- towej. Programy uĪytkowe uruchamiane w Ğrodowisku Windows mają do dyspozycji tzw. páaski model pamiĊci, który moĪna traktowaü jako szczególny przypadek modelu segmentowego. Pokazuje to rysunek 3.14. Rysunek 3.14. Páaski model pamiĊci Wszystkie rejestry segmentowe wskazują w tym modelu na ten sam 4-gigabajtowy segment rozpoczynający siĊ od adresu 0. 10 ZnajomoĞü tych zagadnieĔ jest niezbĊdna w przypadku tworzenia wáasnego systemu operacyjnego. 48 Praktyczny kurs asemblera 3.5. Adresowanie argumentów Instrukcje procesora mogą byü bezargumentowe, mogą mieü jeden, dwa lub trzy argu- menty. Niektóre argumenty wystĊpują w instrukcji jawnie, inne mogą byü zakodowane wewnątrz instrukcji. Argumentami instrukcji mogą byü:  argumenty bezpoĞrednie bĊdące czĊĞcią instrukcji,  rejestry,  argumenty w pamiĊci operacyjnej,  ukáady wejĞcia-wyjĞcia komputera. Omówieniem instrukcji procesorów zajmiemy siĊ dopiero w rozdziale 5., jednak teraz na potrzeby objaĞnienia sposobu adresowania argumentów posáuĪymy siĊ znaną juĪ z pierwszego rozdziaáu instrukcją MOV (kopiuj) oraz instrukcją ADD (dodaj). Dwa pierw- sze (spoĞród wyĪej wymienionych) sposoby adresowania argumentów są, jak siĊ wydaje, oczywiste i moĪemy zilustrowaü je nastĊpującymi prostymi przykáadami: ; dwa argumenty bĊdące rejestrami: mov ax, si ; skopiuj zawartoĞü rejestru indeksowego SI do AX mov edi, ebx ; skopiuj zawartoĞü rejestru bazowego EBX do indeksowego EDI add esi, ebp ; dodaj do rejestru indeksowego ESI zawartoĞü rejestru EBP add cl, ch ; dodaj zawartoĞü rejestru CH do zawartoĞci rejestru CL ; jeden argument bĊdący rejestrem oraz argument bezpoĞredni: mov ah, 2 ; wpisz do rejestru AH liczbĊ 2 (binarnie) mov bp, 0 ; wyzeruj rejestr bazowy BP add cx, 100h ; dodaj do zawartoĞci rejestru CX wartoĞü 100 szesnastkowo add ebx, 0ffh ; dodaj do rejestru EBX wartoĞü 0ff szesnastkowo Adresowaniu argumentów w pamiĊci operacyjnej poĞwiĊcimy caáy nastĊpny podroz- dziaá, jest to bowiem zagadnienie záoĪone i waĪne. Teraz natomiast zajmiemy siĊ adre- sowaniem ukáadów wejĞcia-wyjĞcia. Procesory x86-32 obsáugują przestrzeĔ adresową zawierającą maksymalnie 65 536 (64 k) oĞmiobitowych ukáadów wejĞcia-wyjĞcia (portów we-wy). W przestrzeni tej mogą byü definiowane takĪe porty 16- i 32-bitowe. Porty we-wy moĪna adresowaü bezpoĞred- nio lub za poĞrednictwem rejestru DX. Dla ilustracji posáuĪymy siĊ tutaj instrukcjami procesora: IN (wprowadĨ z ukáadu wejĞciowego) oraz OUT (wyprowadĨ do ukáadu wyjĞciowego). in al, 3f8h ; wprowadĨ do rejestru AL bajt z ukáadu wejĞciowego ; o adresie 3fah mov dx, 0dff0h ; zapisz w rejestrze DX adres portu wejĞciowego in ax, dx ; wprowadĨ do rejestru AX sáowo z ukáadu wejĞciowego, ; którego adres jest zapisany w rejestrze DX out 61h, bl ; wyprowadĨ do ukáadu wyjĞciowego o adresie 61 szesnastkowo ; zawartoĞü rejestru BL mov dx, 378h ; zapisz do rejestru DX adres portu wyjĞciowego out dx, al ; wyprowadĨ do ukáadu wyjĞciowego o adresie znajdującym siĊ ; w rejestrze DX zawartoĞü rejestru AL Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 49 3.6. Adresowanie argumentów w pamiöci operacyjnej Procesory x86-32 pozwalają na zaadresowanie argumentów w pamiĊci operacyjnej na wiele róĪnych sposobów. Poznanie tych sposobów oraz ich wáaĞciwe wykorzystanie w róĪnych konstrukcjach programu jest jedną z waĪniejszych umiejĊtnoĞci programisty. KaĪdy argument w pamiĊci operacyjnej okreĞlony jest przez adres, pod jakim siĊ znaj- duje. Standardowo operacje na danych związane są z segmentem danych wskazywa- nym przez zawartoĞü rejestru segmentowego DS i dlatego najczĊĞciej w programie operujemy jedynie offsetem, czyli adresem wzglĊdem początku segmentu. W obliczaniu koĔcowego offsetu, który nazywaü bĊdziemy takĪe adresem efektywnym, uczestniczyü mogą rejestry procesora naleĪące do jednostki staáoprzecinkowej. I tak:  w procesorze 8086 oraz w nowszych procesorach o architekturze x86-32 pracujących w 16-bitowym trybie adresacji rzeczywistej w obliczaniu adresu efektywnego mogą uczestniczyü rejestry indeksowe DI, SI oraz bazowe BX, BP,  w procesorach o architekturze x86-32 w trybie adresacji rzeczywistej do obliczania adresu efektywnego bĊdzie moĪna wykorzystywaü rejestry 32-bitowe (podobnie jak w trybie adresacji wirtualnej), jednak zasadniczo jest to tryb bazujący na rejestrach 16-bitowych — przez analogiĊ do procesora 808611,  w procesorach x86-32 pracujących w 32-bitowym trybie adresacji wirtualnej w obliczaniu adresu efektywnego mogą uczestniczyü wszystkie rejestry 32-bitowe: EAX, EBX, ECX, EDX, ESI, EDI, EBP i ESP. Dla uproszczenia mówiü bĊdziemy w skrócie o adresowaniu 16-bitowym oraz 32-bito- wym — mając na myĞli wielkoĞü offsetu. DostĊpne tryby adresowania argumentów w pamiĊci operacyjnej w trybie 16-bitowym zebrane są w tabeli 3.4. Rejestr ujĊty w nawiasy kwadratowe oznacza, Īe jego zawartoĞü to offset uczestniczący w obliczaniu adresu efektywnego argumentu w pamiĊci opera- cyjnej. Liczba ujĊta w nawiasy kwadratowe jest wartoĞcią przemieszczenia wzglĊdem początku segmentu, czyli wprost offsetem. WielkoĞü argumentu w pamiĊci operacyjnej wynika jednoznacznie z wielkoĞci drugiego argumentu, którym jest rejestr. NaleĪy jeszcze kolejny raz przypomnieü, Īe standardowo argumenty w pamiĊci adre- sowane w sposób pokazany w tabeli 3.4 znajdują siĊ w segmencie danych wskazywanym przez zawartoĞü rejestru DS, z wyjątkiem tych, dla których w obliczaniu adresu efek- tywnego uczestniczy rejestr bazowy BP. W tym przypadku obliczony adres efektywny dotyczy argumentu w segmencie stosu wskazywanym przez zawartoĞü rejestru SS. W kaĪdym przypadku to standardowe przyporządkowanie segmentów moĪemy zmieniü, dopisując do wyraĪenia nazwĊ rejestru segmentowego zakoĔczoną dwukropkiem, tak jak pokazano to w niektórych przykáadach z ostatniej kolumny w tabeli 3.4. Warto jednak pamiĊtaü, Īe powoduje to powiĊkszenie instrukcji procesora o jednobajtowy przedrostek. 11 Mieszanie 16- i 32-bitowych trybów omówione zostanie w nastĊpnym podrozdziale. 50 Praktyczny kurs asemblera Tabela 3.4. Tryby adresowania w procesorze 8086 Tryb Przez przemieszczenie Skäadnia PoĞrednio przez rejestr bazowy lub indeksowy [BX] [BP] [DI] [SI] Adres efektywny WartoĞü przemieszczenia wyraĪona liczbą bądĨ przez nazwĊ symboliczną ZawartoĞü rejestru PoĞrednio przez rejestr indeksowy i bazowy PoĞrednio przez rejestr bazowy, indeksowy i przemieszczenie (displacement) Suma zawartoĞci obu rejestrów Suma zawartoĞci rejestrów indeksowego i bazowego oraz przemieszczenia (displacement) [BX][DI] lub [BX+DI] [BP][DI] lub [BP+DI] [BX][SI] lub [BX+SI] [BP][SI] lub [BP+SI] disp[BX][DI] lub [BX+DI + disp] disp [BP][DI] lub [BP+DI + disp] disp [BX][SI] lub [BX+SI + disp] disp [BP][SI] lub [BP+SI + disp] Przykäad mov bx, ds:[10] add cx, licznik mov zmienna, ax mov dl, [bx] add bx, [bp] mov [di], ah add [si], cx mov ax, ds:[bp] add bx, [bp+di] mov byte ptr [bx][si], 15 add cs:[bx+si], ax mov ax, [bp][si] mov ax, zmienna[bx][di] add cx, [bp+si+8] add tabela[bx+si+2], al mov 6[bp][di], ch Pracujñc w trybie 16-bitowym, czyli uĔywajñc do generowania adresu efektywnego rejestrów 16-bitowych, warto pamiötaè nastöpujñcy schemat ilustrujñcy wszystkie moĔliwoĈci generowana adresu efektywnego: ª SI « DI ¬ º » ¼ ª « ¬ BX BP º » ¼ ª none « 8 bit « « 16 bit ¬ º » » » ¼ Offset =Index+Base+Displacement W wyraĔeniu adresowym moĔe (ale nie musi) wystñpiè po jednym elemencie z kaĔdej kolumny. JeĔeli w wyraĔeniu wystöpuje rejestr BP, to obliczamy adres efektywny dla argumentu w segmencie stosu (SS), w pozostaäych przypadkach — w segmencie danych (DS). PrzejdĨmy teraz do 32-bitowego adresowania w procesorach x86-32. Procesory te, przy niezmienionej samej idei obliczania adresu efektywnego z wykorzystaniem rejestrów indeksowych, bazowych i przemieszczenia, dają znacznie wiĊksze moĪliwoĞci poprzez fakt, iĪ w obliczaniu adresu efektywnego moĪe uczestniczyü kaĪdy z 32-bitowych reje- strów procesora: EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP. KaĪdy z wymienionych rejestrów moĪe peániü funkcjĊ rejestru bazowego bądĨ indeksowego. Wyjątkiem jest Rozdziaä 3. i Architektura procesorów rodziny x86-32 widziana oczami programisty 51 rejestr ESP, który nie moĪe peániü roli rejestru indeksowego. Dodatkowo zawartoĞü reje- stru traktowanego jako indeksowy moĪe byü przemnoĪona przez wspóáczynnik skali o wartoĞci 1, 2, 4 lub 8. Przemieszczenie, jeĪeli wystĊpuje, moĪe byü 8-, 16- lub 32-bitowe. Nie moĪna mieszaü w wyraĪeniu adresowym rejestrów 16- i 32-bitowych. PoniĪej pokaĪemy przykáady poprawnych instrukcji procesora wykorzystujących adresowanie argumentów w pamiĊci za pomocą 32-bitowych rejestrów: .386 ; bĊdziemy stosowaü rozkazy procesora 80386 mov eax, [edx+10] mov esi, [edx][eax] mov tablica[ecx+ebp], bl add [esi*2], eax add eax, tablica[ecx*4][edx+2] add bx, es:[eax+ebp+1] add al, [ecx*1] ; to teĪ jest poprawne, ECX peáni rolĊ ; rejestru indeksowego Reguáy przyporządkowania segmentów w 32-bitowym trybie adresowania moĪna zapi- saü w nastĊpujących punktach:  jeĞli rejestrem bazowym jest EBP lub ESP, to standardowym rejestrem segmentowym jest SS, we wszystkich pozostaáych przypadkach jest to rejestr DS,  jeĪeli w wyraĪeniu wystĊpują dwa rejestry, tylko jeden z nich moĪe mieü wspóáczynnik skalowania; rejestr ze wspóáczynnikiem skalowania jest wtedy rejestrem indeksowym,  jeĪeli skalowanie nie jest stosowane, to pierwszy rejestr w wyraĪeniu jest rejestrem bazowym. PowyĪsze zasady ilustrują nastĊpujące przykáady: mov eax,[edx] ; EDX jest rejestrem bazowym – segment DS mov eax,[ebp][edx] ; EBP jest rejestrem bazowym (jest pierwszy) – segment SS mov eac,[edx][ebp] ; EDX jest rejestrem bazowym (jest pierwszy) – segment DS mov eax,[edx*2][ebp] ; EBP jest rejestrem bazowym (nie skalowany) – segment SS mov eax,[edx][ebp*8] ; EDX jest rejestrem bazowym (nie skalowany) – segment DS Sposoby obliczania adresu efektywnego w trybie 32-bitowym moĔna przedstawiè za pomocñ nastöpujñcego schematu: Podobnie jak w schemacie dla adresowania 16-bitowego, w wyraĔeniu adresowym moĔe wystñpiè po jednym elemencie z kaĔdej kolumny. 52 Praktyczny kurs asemblera 3.7. Architektura x86-32e Wspóáczesne procesory x86-32, począwszy od roku 2003 (niektóre modele procesora Pentium 4 oraz wszystkie nastĊpne, takie jak: Core 2 oraz Core i7), posiadają dodatkowy 64-bitowy tryb pracy. Warto zatem przynajmniej zasygnalizowaü, jakie nowe moĪliwoĞci pojawią siĊ przed programistą w jĊzyku asemblera, gdy odpowiednie narzĊdzia staną siĊ dostĊpne w takim samym stopniu jak narzĊdzia 32-bitowe. ArchitekturĊ 64-bitową wprowadziáa do procesorów o architekturze x86-32 po raz pierw- szy firma AMD, nazywając ją x86-64. Firma Intel, wprowadzając do swoich procesorów to rozwiązanie, uĪyáa początkowo nazwy x86-32e dla podkreĞlenia, Īe jest to archi- tektura „rozszerzona” (ang. extension). Inna nazwa tego rozszerzenia uĪywana przez firmĊ Intel to EM64T (ang. Extended Memory 64 Technology). Obecnie oficjalnie uĪywana jest nazwa Intel 64, której nie naleĪy myliü z architekturą IA-64, w oparciu o którą zbudowana jest zupeánie inna linia procesorów opracowanych przez firmy Hewlett-Packard oraz Intel, o nazwie Itanium. Rysunek 3.15, zaczerpniĊty z dokumentacji firmy Intel, ilustruje umiejscowienie trybu x86-32e oraz moĪliwe przejĞcia miĊdzy poszczególnymi trybami. Nie zagáĊbiając siĊ w szczegóáy niebĊdące przedmiotem rozwaĪaĔ w tej ksiąĪce, moĪemy jednak zauwaĪyü, Īe „dojĞcie” do trybu x86-32e odbywa siĊ od trybu adresacji rzeczywistej (od którego procesor rozpoczyna pracĊ po podáączeniu do zasilania) poprzez 32-bitowy tryb adresacji wirtualnej z ochroną (Protected Mode), bĊdący gáównym przedmiotem zainteresowania w tej ksiąĪce. Rysunek 3.15. PrzejĞcia miĊdzy poszczególnymi trybami procesora o architekturze x86-32 (na podstawie dokumentacji firmy Intel) W trybie 64-bitowym programista otrzymuje powiĊkszone do 64 bitów rejestry ogól- nego przeznaczenia RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, na których mapo- wane są omówione w poprzednich podrozdziaáach 32-bitowe rejestry, odp
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Praktyczny kurs asemblera. Wydanie II
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: