Assembly HOWTO: ASSEMBLERY
Następna strona
Poprzednia strona
Spis treści
3. ASSEMBLERY
3.1 Inline Assemblera GCC
Dobrze znany kompilator GNU C/C++ (GCC),
zoptymalizowany 32-bitowy kompilator będący sercem projektu GNU,
wspiera całkiem dobrze architekturę x86,
włączając w to zdolność wstawiania kodu assemblera w programach w C,
w sposób gdzie zarządzanie rejestrami może być wyspecyfikowane lub pozostawione GCC.
GCC działa na większości dostępnych platform,
dla godnych uwagi Linux-a, *BSD, VST, OS/2, *DOS-a, WIN*, itd.
Gdzie znaleźć GCC
Orginalny adres GCC jest adresem FTP GNU
ftp://prep.ai.mit.edu/pub/gnu/
razem ze wszystkimi wersjami aplikacji z projektu GNU.
Przekompilowane i skonfigurowane dla Linux-a wersje są w
ftp://sunsite.unc.edu/pub/Linux/GCC/
Istnieje wiele kopii FTP obu adresów,
na całym świecie a także na nośnikach CD.
Rozwój GCC został podzielony niedawno na dwie części.
Więcej na temat eksperymentalnej wersji egcs mozna znaleźć na
http://www.cygnus.com/egcs/Źródła przystosowane do twojej ulubionego OS, oraz przekompilowane binaria
można znaleźć na zwykłych adresach FTP.
Najbardziej popularny port GCC dla DOS-a nosi nazwę DJGPP
i może być znaleziony w katalogach o takiej nazwie na adresach FTP. Zobacz:
http://www.delorie.com/djgpp/Jest także port GCC na OS/2 nazwany EMX,
działający także pod DOS-em,
zawierający wiele bibliotek emulujących wywołania funkcji unix-a.
Zobacz:
http://www.leo.org/pub/comp/os/os2/gnu/emx+gcc/
http://warp.eecs.berkeley.edu/os2/software/shareware/emx.html
ftp://ftp-os2.cdrom.com/pub/os2/emx09c/
Gdzie znaleźć dokumentacje GCC Inline Asm
Dokumentacja GCC zawiera pliki w formacie texinfo.
Możesz przekompilować je TeX-em i wydrukować rezultat,
lub przekonwertować je do .info i oglądać emacs-em,
lub przekonwertować je do .html.
Możesz przekonwertować je (właściwymi narzędziami) do tego co lubisz najbardziej, lub czytać takie jakie są.
Pliki .info są ogólnie dostarczane z każdą dobrą instalacją GCC.
Właściwą sekcją do sprawdzenia jest:
C Extensions::Extended Asm::
Sekcja
Invoking GCC::Submodel Options::i386 Options::
może być ci także pomocna.
W szczególności, podaje ci specyficzne ograniczenia nazw rejestrów:
abcdSDB korespondują do
%eax, %ebx, %ecx, %edx,
%esi, %edi, %ebp
wyłączając (nie ma litery dla %esp).
Zasoby gier dla DJGPP (nie tylko dla hackerów gier) mają swoją stronę
specjalnie o assemblerze:
http://www.rt66.com/~brennan/djgpp/djgpp_asm.htmlJest jeszcze strona www nazwana ``DJGPP Quick ASM Programming Guide'',
zawierająca od URL-i do FAQ,
AT&T Składnia ASM x86 ,
Pewne informacje o inline ASM,
i konwertowanie plików .obj/.lib:
http://remus.rutgers.edu/~avly/djasm.htmlGCC zależy od GAS podczas assemblacji, i śledzi jego składnię (patrz poniżej);
pamiętając że inline asm wymaga znaków procent podczas cytowania
by mogły przejść do GAS.
Zobacz poniższą sekcję o GAS.
Znajdziesz pełno użytecznych przykładów w podkatalogu linux/include/asm-i386/
źródeł jądra Linux-a.
Jak właściwie wywoływać GCC z kodem inline assemblera.
Ponieważ funkcje assemblera w źródłach jądra
(i bardzo prawdopodobnie twoje własne nagłówki,
jeśli spróbujesz stworzyć twoje oprogramowanie w assemblerze tak czyste
jak to jest w jądrze linuxa)
są osadzone w funkcjach extern inline,
GCC musi zostać wywołąny z -O flag (or -O2, -O3, itd),
by te funkcje były dostępne.
Jeśli nie, twój kod może się skompiluje, ale nie zostanie właściwie zlinkowany,
gdyż będzie szukał funkcji extern które nie są inline
w bibliotekach z którymi twój program będzie linkowany !!!.
Innym sposobem jest zlinkowanie z bibliotekimi zawierającymi wycofane
wersje tych funkcji.
Assemblacja inline może zostać wyłączona opcją -fno-asm,
która każe zaprzestać kompilatorowi działania gdy zostanie użyte rozszerzenie składni o inline asm,
w przeciwnym wypadku wygeneruje wywołanie funkcji zewnętrznej o nazwie asm(),
która nie zostanie właściwie rozwiązana przez linker.
Opcja -fasm przywraca działanie słowa kluczowego asm.
Bardziej ogólnie, dobrymi opcjami dla GCC na platformie x86 są
gcc -O2 -fomit-frame-pointer -W -Wallpp
-O2 jest dobrym poziomem optymalizacji w większości przypadków.
Optymalizacja ponadto zajmuje więcej czasu, otrzymując kod który jest mocno dłuższy, ale tylko trochę szybszy;
taka optymalizacja może być użyteczna tylko dla ciasnych pętli (jeśli takie są),
którą możesz jakkolwiek zrealizować w assemblerze.
W przypadkach gdy koniecznie potrzebujesz silnej optymalizacji ze strony kompilatora dla kilku plików, rozważ użycie -O6.
-fomit-frame-pointer pozwala generować kod omijający głupie
zarządzanie ramką wskaźników, co daje mniejszy i szybszy kod,
i zwalnia rejestry do dalszych optymalizacji.
Wyklucza to łatwe użycie narzędzi odpluskwiających (gdb),
ale kiedy chcesz ich użyć, nie martw się o rozmiar i prędkość kodu.
-W -Wall włącza generowanie wszytkich ostrzeżeń i pomaga wychwycić
głupie błędy.
Możesz dodać specyficzne dla danego procecora -m486 lub inne flagi tak, że
GCC wyprodukuje kod bardziej zaadaptowany dla danego komputera.
Zauważ, że EGCS (i chyba GCC 2.8) mają -mpentium i tego typu flagi,
podczas gdy GCC 2.7.x i starsze wersje nie.
Niezły wybór flag specyfikujących procesor powinien być w jądrze Linux-a.
Sprawdź dokumentację texinfo o zainstalowanej u ciebie wersji GCC.
-m386 pomoże zoptymalizować wielkość,
a także prędkość na komputerach gdzie pamięć jest w pełni wykorzystana,
odkąd wielkie programy są przyczyną wymiany pamięci,
jakakolwiek "optymalizacja" jest sensowna dla większego kodu.
Przy takich ustawieniach, może być pomocne przestanie korzystania z C,
i w zamian skorzystanie z języka ułatwiającego kod faktoryzujący (przyp.tłum.)
taki jak funkcjonalny język i/lub FORTH;
i używać implementacji bazującej na wykorzystaniu bajtów i słów.
Zapamiętaj, że możesz używać rożnych flag dla różnych plików,
więc używaj maksymalnej optymalizacji tam, gdzie program wykonuje się najdłużej,
podczas gdy pozostałe pliki optymalizuj pod względem rozmiaru.
Do optymalizacji może być pomocna opcja -mregparm=2
i/lub korespondujące atrybuty funkcji,
ale mogą stwarzać wiele problemów podczas linkowania obcego kodu,
włączająć w to libc.
Są sposoby by właściwie zadeklarować użycie obcych funkcji,
tak, że zostaną wygenerowane właściwe wywołania,
lecz możesz być zmuszony rekompilować obce biblioteki tak,
by używały takich samych konwencji wywołań opartych na rejestrach...
Zapamiętaj, że możesz ustawić te flagi jako domyślne edytując plik
/usr/lib/gcc-lib/i486-linux/2.7.2.3/specs
lub gdziekolwiek on jest w twoim systemie (lepiej nie dodawaj tam -Wall).
Dokładną lokalizację plików specyfikatorów GCC w twoim systemie
możesz uzyskać wołająć gcc -v.
3.2 GAS
GAS jest GNU Assemblerem, na którym opiera się GCC.
Gdzie go znaleźć
Znajdziesz go w tym samym miejscu gdzie GCC,
w paczce o nazwie binutils.
Jaka jest składnia AT&T
W związku z tym, że GAS został pomyślany by wspierać 32-bitowe kompilatory unixowe
używa on standardowej składni ``AT&T'',
która składnią mocno przypomina standardowe assemblery m68k,
i jest standardem w świecie UNIX-a.
Składnia nie jest ani gorsza, ani lepsza niż składnia ``Intel-owska''.
Jest po prostu inna.
Kiedy będziesz zamierzał używać jej,
zauważysz bardziej regularna składnię niż w Intel-u,
chociaż trochę nudniejszą.
Oto najważniejsze ostrzeżenia odnośnie składni GAS:
Nazwy rejestrów są poprzedzone %, więc
wygląd rejestrów %eax, %dl itd
zamiast tylko eax, dl, itd.
Dzięki temu możliwe jest włączanie zewnętrznych symboli w C bezpośrednio
w kodzie assemblera, bez zamieszania i konieczności
stosowania okropnych podkreśleń jako przedrostków.
Kolejność operandów jest następująca: pierwsze źródło, ostatnie przeznaczenie,
w przeciwieństwie do konwencji intel-a, gdzie pierwsze jest przeznaczenie,
a ostatnie źródło.
Odtąd, to co w składni intel-a jest mov ax,dx (wstaw rejestr
dx w rejestr ax w składni att będzie wyglądało następująco:
mov %dx, %ax.
Długość operandu jest wyspecyfikowana przez przyrostek w nazwie instrukcji.
Przyrostkiem jest b dla (8-bitów) bajtu,
w dla (16-bitów) słowa,
i l dla (32-bitów) podwójnego słowa.
Na przykład, właściwą składnią powyższej instrukcji
będzie movw %dx,%ax.
Jakkolwiek, gas nie wymaga ścisłej składni att,
więc przyrostek jest opcjonalny, kiedy długość operandu może być wywnioskowana z
rejestrów, w przeciwnym przypadku, domyślnie zostanie wstawiony 32-bitowy operand (z ostrzeżeniem).
Wymuszające operandy zaznaczone są przyrostkami $,
tak jak w addl $5,%eax
(dodaj wymuszające long dla wartość 5 do rejestru %eax).
Brak przedrostka w operandzie wskazuje, że jest to adres w pamięci;
stąd movl $foo,%eax
wstawia zawartość adresu zmiennej foo w rejestr %eax,
ale movl foo,%eax
wstawia zawartość zmiennej foo w rejestr %eax.
Indeksacja lub wskazanie pośrednie jest realizowane przez umieszczenie
rejestru indeksowego lub wskazania pośredniego (komórki wskazania
pośredniego) w nawiasach,
np testb $0x80,17(%ebp)
(sprawdza najstarszy bit bajtu o offsecie 17
z komórki wskazanej przez %ebp).
Istnieje program pomagający w konwersji programów
ze składni TASM do składni AT&T. Zobacz
ftp://x2ftp.oulu.fi/pub/msdos/programming/convert/ta2asv08.zipGAS ma obszerną dokumentację w formacie TeXinfo,
którą można znaleźć co najmniej w dystrybucji źródłowej.
Przegląd wyciągniętych stron .info z Emacs-a lub innych programów.
Zdarzały się pliki o nazwach gas.doc lub as.doc
gdzieś w pakietach źródłowych GAS, ale zostały włączone w dokumentacje TeXinfo.
Oczywiście, w razie wątpliwości, alternatywną dokumentacją
są same źródła!
Sekcją, która szczególnie cię zainteresuje to
Machine Dependencies::i386-Dependent::
Znowu, źródła Linux-a (jądra systemu), są dobrymi przykładami;
zobacz w linux/arch/i386, następujące pliki:
kernel/*.S, boot/compressed/*.S, mathemu/*.S
Jeśli piszesz jakiś język, pakiet obsługi wątków, itd.
możesz obejrzeć jak inne języki (OCaml, gforth, itd.),
lub pakiety obsługi wątków (QuickThreads, MIT pthreads, LinuxThreads, itd),
lub cokolwiek, zrób to.
Na końcu, po prostu skompiluj program w C do assemblera
dzięki czemu zobaczysz interesującą cię składnię.
Zobacz sekcję
Czy potrzebuję Assemblacji?.
Ograniczony tryb 16-bitowy
GAS jest 32-bitowym assemblerem, zadaniem którego jest wspomóc 32-bitowy kompilator.
Aktualnie ma on jedno ograniczenie 16-bitowego trybu,
który zawiera niedokończone użycie 32-bitowych przedrostków do instrukcji,
tak więc piszesz 32-bitowy kod, który chodzi w 16-bitowym trybie na 32 bitowym procesorze.
W obu trybach, wspiera on 16-bitowe używanie rejestrów,
ale nie wspiera 16-bitowego adresowania.
Użycie dyrektywy .code16 and .code32 przełącza pomiędzy trybami.
Zapamiętaj, że dyrektywa inline assembly
asm(".code16\n")
pozwoli GCC wygenerować 32-bitowy kod, który uruchomi się w trybie rzeczywistym!
Stwierdziłem już, że większa część kodu potrzebnego do pełnego wspomagania
16-bitowego trybu programowania została dodana do GAS przez Bryan'a Ford'a (proszę o potwierdzenie?),
ale ostatecznie, nie pojawiła się w żadnej dystrybucji którą sprawdziłem,
aż do binutils-2.8.1.x ... więcej informacji na ten temat będzie mile widziane.
Cienkim rozwiązaniem jest definiowanie makr (patrz poniżej), które produkuja
kod binarny (z .byte) który potrzebujesz tylko dla 16-bitowych instrukcji
(prawie żadnych jeśli użyjesz code16 jak powyżej,
i możesz spokojnie założyć, że kod będzie działał na zgodnych 32-bitowych procesorach x86).
By znaleźć właściwe kodowanie, możesz zainspirować się
źródłami 16-bitowych assemblerami.
3.3 GASP
GASP jest Preprocesorem GAS.
Dodaje makra i trochę milszą składnię do GAS.
Gdzie znaleźć GASP
GASP jest zawarty razem z GAS w archiwum GNU binutils.
Jak to działa
Działa jako filtr, w stylu cpp i jemu podobnym.
Nie pamiętam szczegółów, ale przychodzi on z własną dokumentacją w texinfo,
więc przejrzyj ją (w .info), wydrukuj, prześledź (?).
GAS z GASP-em według mnie jest typowym makro-assemblerem.
3.4 NASM
Projekt Netwide Assembler wypuszcza jeszcze jeden assembler,
napisany w C, który powinien być dość modelowy
do ewentualnego wsparcia znanych składni i formatów obiektów.
Gdzie znaleźć NASM
http://www.cryogen.com/NasmWersja binarna jest na kopii sunsite w
devel/lang/asm/
Powinna być także dostępna jako .rpm lub .deb w dystrybucjach RedHat/Debian
w dystrybucyjnym contrib.
Co to robi
W momencie pisania tego HOWTO, wersja NASM to 0.97.
Składnia jest w stylu Intel-a.
Część makroprocesora jest zintegrowana.
Wspierane formaty plików obiektowych to
bin, aout, coff, elf, as86,
(DOS) obj, win32, (ich własny format) rdf.
NASM może być używany jako wspomaganie dla wolnego kompilatora LCC
(pliki wspierające są zawarte).
NASM rozwija się zbyt szybko by to HOWTO było aktualne.
Jeżeli nie używasz BCC jako 16-bitowego kompilatora
(który wykracza poza to 32-bitowe HOWTO),
powinieneś używać NASM zamiast powiedzmy AS86 lub MASM,
ponieważ jest mocno wspierany online
i chodzi na wszystkich platformach.
Uwaga: NASM przychodzi także z disassemblerem, NDISASM.
Jego ręcznie napisany parser powoduje, że pracuje szybciej niż GAS,
chociaż oczywiście nie wspiera trzech bilionów różnych architektur.
Do x86, on powienien być assemblerem wyboru...
3.5 AS86
AS86 jest 80x86 16- i 32-bitowym assemblerem i jest częścią
kompilatora języka C (BCC) Bruce'a Evans'a.
Ma on głównie składnię Intel-owską,
chociaż różni się nieznacznie np w trybach adresowania.
Gdzie dostać AS86
Całkowicie przestarzała wersja AS86 jest dystrybuowana przez HJLu
tylko do kompilacji jądra Linux-a,
w pakiecie o nazwie bin86 (aktualna wersja 0.4),
dostępnej w dowolnym magazynie oprogramowania GCC dla Linux-a.
Ale nie radzę nikomu używania go do czegokolwiek innego niż przekompilowania Linux-a.
Ta wersja wspiera tylko plik obiektowy hacked minix,
który nie jest wspierany przez GNU binutils ani nic innego,
i ma parę błędów w trybie 32-bitowym,
więc powienieneś lepiej trzymać go tylko do kompilacji Linux-a.
Ostatnie wersje Bruce'a Evans'a (bde@zeta.org.au)
są publikowane wraz z dystrybucją FreeBSD.
No, były: Nie mogę znaleźć źródeł z dystrybucji 2.1 na :(
Odtąd, wkładam źródła w moim miejscu:
http:///www.tunes.org/~fare/files/bcc-95.3.12.src.tgzProjekt Linux/8086 (aka ELKS) jest w pewnym stopniu pozostałością bcc
(chociaż nie sądze by zawierał 32-bitowe łaty).
Obejrzyj
http://www.linux.org.uk/Linux8086.html
ftp://linux.mit.edu/.
Między innymi, ostatnie wersje, w przeciwieństwie do HJLu's,
wspierają Linux-owy format GNU a.out,
więc możesz linkować twój kod z programami Linux-owymi, i/lub używać zwykłych
narzędzi z pakietu GNU binutil do manipulacji danymi.
Ta wersja może ko-egzystować bez szkody z poprzednią wersją
(zobacz poniższe pytanie).
BCC z 12 marca 1995 roku i wcześniejsze jego wersje mają brak składnika jakim
jest odkładanie/pobieranie ze stosu rejestrów segmentowych jako 16-bitowych,
co jest uciążliwe gdy programujesz w trybie 32-bitowym.
Łata jest opublikowana w projekcie Tunes
http://www.tunes.org/
podstrona
files/tgz/tunes.0.0.0.25.src.tgz
w rozpakowanym katalogu
LLL/i386/
Łata powinna być także dostępna bezpośrednio z
http://www.tunes.org/~fare/files/as86.bcc.patch.gz
Bruce Evans zaakceptował tę łatę, więc jeśli któregoś dnia pojawi się
nowa wersja bcc, powinna zawierać tę łatę...
Jak wywołać assembler?
Oto wpis GNU Makefile do używania bcc
do transformacji .s asm
w oba GNU a.out .o obiekt
i .l listing:
%.o %.l: %.s
bcc -3 -G -c -A-d -A-l -A$*.l -o $*.o $<
Usuń %.l, -A-l, and -A$*.l,
jeśli nie chcesz listingu.
Jeśli chcesz czegoś więcej niż GNU a.out,
możesz przejrzeć dokumentację bcc o wspieranych formatach,
i/lub użyć objcopy z pakietu GNU binutils.
Gdzie znaleźć dokumentacje
Dokumentacje które są, zawierają się w pakiecie bcc.
Podręczniki są także dostępne gdzieś pod adresem FreeBSD.
Kiedy masz wątpliwości, źródła same w sobie są często dobrą dokumentacją:
to nie jest zbyt dobrze komentowane, ale styl programowania jest zrozumiały.
Możesz spróbować obejrzeć jak as86 jest używany w Tunes 0.0.0.25...
Co jeśli nie mogę już skompilować Linux-a z nową wersją ?
Linus jest zasypywany listami i moja łata kompilująca Linux-a
z Linuxowym a.out as86 chyba do niego nie dotarła (!) (od tłum. trudno to przetłumaczyć - proszę o poprawki).
Teraz, nie powinno to mieć znaczenia: trzymaj tylko as86 z pakietu bin86
w /usr/bin i daj zainstalować bcc dobry as86 w
/usr/local/libexec/i386/bcc/as
gdzie powinien być. Nie będziesz nigdy wołał wprost tego ``dobrego'' as86,
ponieważ bcc robi wszystko właściwie, włączając konwersję to Linux-owego a.out,
gdy jest wywołany z właściwymi opcjami;
więc assembluj pliki wyłącznie z bcc jako głownym assemblerem, nie bezpośrednio z as86.
3.6 INNE ASSEMBLERY
To są inne, nieregularne, opcje,
w przypadku, gdy powyższe cię niesatysfakcjonowały (dlaczego?),
których nie zalecam w przypadku użytkowania (?),
ale mogę udowodnić użyteczność jeśli assembler musi być zintegrowany
w oprogramowaniu które rozwijasz (np. OS lub aplikacje rozwojowe).
Win32Forth assembler
Win32Forth jest wolnym 32-bitowym systemem ANS FORTH
który działa pod Win32s, Win95, Win/NT.
Zawiera wolny 32-bitowy assembler (zawiera przed/przyrostkową składnię)
zintegrowany w języku FORTH.
Przetwarzanie makr jest przez
pełną moc języka FORTH;
jakkolwiek, jedynym wspieranym wejścia i wyjścia jest Win32For
(żadnego zrzutu do plików .obj -- możesz oczywiście dodać to samemu).
Znajdziesz to na
ftp://ftp.forth.org/pub/Forth/win32for/
Terse
Terse jest narzędziem programowania dostarczającym
NAJBARDZIEJ zwartą składnie assemblera
dla rodziny x86!
Zobacz
http://www.terse.com.
Mówiono, że jest gdzieś jakiś wolny klon
który został porzucony po pustych pretensjach, że składnia
powinna być własnością autora;
i zapraszam cię do przejęcia tego,
jeśli taka składnia cię interesuje.
Nie-wolne i/lub Nie-32bitowe x86 assemblery.
Możesz znaleźć więcej o nich,
wraz z podstawami programowania w assemblerze x86
w FAQ Raymond'a Moon'a dla comp.lang.asm.x86
http://www2.dgsys.com/~raymoon/faq/asmfaq.zipZapamiętaj, że wszystkie bazujace na DOS-ie assemblery powinny pracować w Linuxowym emulatorze DOS-u
tak dobrze jak inne podobne emulatory, więc jeśli już masz jakiś
możesz go nadal używać w prawdziwym OS.
Ostatnie assemblery bazujące na DOS-ie także wspierają COFF i/lub inne formaty
plików obiektowych, które są wspierane przez bibliotekę GNU BFD,
więc możesz używać ich razem z wolnymi 32-bitowymi wolnymi narzędziami,
być może używająć GNU objcopy (część binutils) jako filtr konwertujący.
Następna strona
Poprzednia strona
Spis treści
Wyszukiwarka
Podobne podstrony:
Assembly HOWTO pl 5 (2)Assembly HOWTO pl 4 (2)assembly howto plAssembly HOWTO pl 7 (2)Assembly HOWTO pl (2)Assembly HOWTO pl 6 (2)Assembly HOWTO pl 2 (2)Assembly HOWTO pl 1 (2)bootdisk howto pl 8PPP HOWTO pl 6 (2)NIS HOWTO pl 1 (2)cdrom howto pl 1jtz howto pl 5Keystroke HOWTO pl (2)PostgreSQL HOWTO pl 14printing howto pl 5debian apt howto plKernel HOWTO pl 12 (2)XFree86 HOWTO pl (3)więcej podobnych podstron