Tutorial 1: Podstawy

Przypuszcam że użytkownik tego Tuta wie jak obsługiwać MASM. Jeżeli nie, ściągnij win32asm.exe i przestudiuj texty w tym archiwum zanim pójdziesz dalej. Dobrze !. Jesteś teraz gotowy :) Możemy zaczynać !

Teoria:

Programy pod Win32 uruchamiają się w trybie chronionym, który jest dostępny od 80286. Ale 80286 to już historia. Więc musimy się tylko przejmować 80386 i jego następcami. Windows uruchamia każdy program w oddzielnej przestrzeni wirtualnej. Oznacza to, że każdy prog pod windows ma swoje własne 4GB adresowalnej pamięci. Jednak nie ozancza to, że każdy winows'owy program ma 4GB fizycznej pamięci, tylko że program może zaadresować każdy adres w tym przedziale. Windows zrobi wszystko co konieczne, by referencje programu do pamięci były prawidłowe. Oczywiście program musi przestrzegać zasad ustanowionych przez Windows, inaczej spowoduje piękny General Protection Fault. Każdy program jest sam w swojej przestrzeni adresowej. Jest to kontrast do sytuacji z Win16. Wszystkie programy Win16 mogą *widzieć* siebie nawzajem. Pod Win32 jest inaczej. Ta cecha pomaga zredukować szanse, że jeden program zapisze coś do kodu/danych innego programu.
Model pamięci jest także drastycznie inny niż w starych czasach "16-bitowego świata". Pod Win32 nie musimy się już przejmować modelem pamięci ani segmentami ! Jest tylko jeden model pamięci: Model pamięci Flat (płaski). Nie ma już 64K segmentów. Pamięć jest wielką 4-gigową przesrzenią. Oznacza to też, że już nie będziesz musial się bawić rejestrami segmentów. Możesz użyć każdego rejestru segmentu, aby zaadresować jakikolwiek punkt w pamięci. To BARDZO pomaga programistą. Czyni to programowanie Win32asm tak proste jak C.
Kiedy programujesz pod Win32, musisz znać kilka podstawowych reguł. Jedna z tych reguł mówi, że Windows używa esi, edi, ebp i ebx wewnętrznie i nie oczekuje zmiany wartości w tych rejestrach. Więc pamiętaj tą pierwszą regułę: jeżeli użyjesz jakiegokolwiek z tych czterech rejestrów w swojej funkcji, nie zapomnij ich przywrócić do poprzedniego stanu zanim oddasz kontrolę w ręce Windows. Funkcja ta jest twoją własną funkcją wywoływaną przez Windows. Oczywistym przykładem jest procedura Windows. Nie oznacza to, że nie możesz używać tych czterech rejestrów, możesz. Ale pamiętaj by je przywrócić zanim wyjdziesz do Windows.

Zawartość:

To jest szkielet programu. Jeżeli czegoś nie rozumiesz, nie panikuj. Wszystko wytłumaczę później.

.386
.MODEL Flat, STDCALL
.DATA
    <Twoje zainicjowane dane>
    ......
.DATA?
   <Twoje niezainicjowane dane>
   ......
.CONST
   <Twoje stałe>
   ......
.CODE
   <Etykieta>
    <Twój kod>
   .....
    end <Etykieta>


To wszystko! Przeanalizujmy ten szkielet :)

.386
To jest dyrektywa assemblera, mówiąca aby użył zestawu instrukcji 80386. Możesz też użyć .486, .586 ale najbezpieczniej jest się trzymać .386. Aktualnie występują dwie prawie identyczne formy dla każedgo modelu CPU. .386/.386p, .486/.486p. Te wersje "p" są konieczne tylko wtedy, gdy program używa instrukcji uprzywilejowanych. Instrukcje uprzywilejowane są to instrukcje zarezerwowane przez CPU/system operacyjny w trybie chronionym. Mogą zostać użyte tylko przez uprzywilejowany kod, taki jak sterownik urządzenia wirtualnego (VxD). Przez większość czasu twój program będzie pracował w trybie nieuprzywilejowanm więc bezpieczniej jest używać wersji bez "p".

.MODEL FLAT, STDCALL
.MODEL - w assemblerze dyrektywa ta specyfikuje model pamięci twojego programu. Pod Win32 jest tylko jeden model pamięci, model FLAT .
STDCALL mówi MASM'owi o sposobie przechodzenia parametrów. Sposób przechodzenia parametrów określa kolejność przechodzenia parametrów - z lewej do prawej albo z prawej do lewej, a także kto zbalansuje budowę stosu po wywołaniu funkcji.
Pod Win16, są dwa sposoby wywoływania - C i PASCAL
Wywoływanie C czyta parametry od prawej do lewej , czyli parametr najbardziej na prawo jest ładowany pierwszy. Wywołujący jest odpowiedzialny za zbalansowanie budowy stosu po wywołaniu. Na przykład, aby wywołać funkcję o nazwie foo (int pierwszy_parametr, int drugi_parametr, int trzeci parametr) sposobem C kod asm będzie wyglądał tak:

push  [third_param]               ; Daj na stos trzeci parametr
push  [second_param]          ; Po czym drugi
push  [first_param]                ; i pierwszy
call    foo
add    sp, 12                             ; Wywołujący balansuje budowę stosu
Wywoływanie PASCAL jest odwrotnością sposobu C. Czyta parametry od lewej do prawej, a wywołujący jest odpowiedzialny za zbalansowanie budowy stosu po wywołaniu.
Win16 zaadoptował wywołanie
PASCAL ponieważ produkuje ono krótszy kod. Wywołanie C jest przydatne, gdy nie wiesz ile parametrów będzie przydzielone funkcji, jak w przypadku wsprintf(), funkcja ta nie ma jak określić ile parametrów zostanie ułożonych na stosie, więc nie może go zbalansować.
STDCALL jast połączeniem wywołań C i PASCAL. Czyta parametry od prawej do lewej, ale to wywołujący jest odpowiedzialny za zbalansowanie stosu po wywołaniu. Platforma Win32 używa STDCALL prawie zawsze. Poza jednym przypadkiem: wsprintf(). Do wsprintf() musisz użyć wywołania C.

.DATA
.DATA?
.CONST
.CODE

Te cztery dyrektywy są czymś co nazywa sie sekcją. Pamiętasz, że w Win32 nie ma segmentów ? Ale możesz podzielić całą twoją pamięć adresową na logiczne sekcje. Początek jakiejś sekcji określa koniec poprzedniej. Są dwie grupy sekcji: data i code. Sekcje data są podzielone na 3 kategorie:

Nie musisz używać wszystkich trzech sekcji w swoim programie. Zadeklaruj tylko te sekcje, które chcesz użyć.

Jest tylko jedna sekcja dla kodu: .CODE. To tutaj znajduje się twój kod.

<Etykieta>
end <Etykieta>
gdzie <Etykieta> jest dowolną etykietą używaną do określenia obszaru twojego kodu. Obie etykiety muszą być identyczne.  Cały twój kod musi znajdować się pomiędzy <Etykieta> i end <Etykieta>


[Strona główna Iczelion's Win32 Assembly]

[Text został przetłumaczony przez WercY]