Asembler x86/Narzędzia: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Mythov (dyskusja | edycje)
Mythov (dyskusja | edycje)
Nie podano opisu zmian
Linia 74:
Określa że w tym miejscu kończy się kod. Asembler po napotkaniu tego słowa kończy proces asemblacji, niezależnie od tego, czy znajduje się jakiś kod jeszcze dalej.
 
=== Hello World! (NASM) ===
<pre>
segment dane
Linia 81:
segment stosik stack
resb 64
szczyt_stosu:
 
segment codekod
..start:
mov ax, dane
Linia 89 ⟶ 88:
mov ax, stosik
mov ss, ax
mov sp, szczyt_stosu
mov dx, tekst
Linia 98 ⟶ 96:
end
</pre>
 
segment dane
Oznacza, że od tego miejsca w dół definiowany jest nowy segment o nazwie "dane".
 
tekst db "Hello World!",0Ah,0Dh,"$"
Ta linijka dodaje zmienną do obecnie definiowanego segmentu (w tym przypadku chodzi o segment "dane"). ''tekst'' to nazwa naszej zmiennej, ''db'' to typ naszej zmiennej (db - 1 bajt) zaś wszystko co znajduje się dalej w tej linijce to wartość początkowa dla naszej zmiennej. Jak widać jest to ciąg znaków zakończony znakami 0A0D (określające przejście do nowej linii) oraz znakiem $ oznaczającym koniec naszego ciągu (dla migrantów z C/C++ - jest to odpowiednik znaku '\0'). Gdyby zabrakło tego znaku, instrukcje operujące na naszej zmiennej, nie mogłyby określić gdzie jest jej koniec, więc wyjechałyby poza przydzielony jej obszar pamięci dopóki nie znalazłyby znaku $.
 
segment stosik stack
Tworzy segment stosu o nazwie ''stosik''...
 
resb 64
... i rozmiarze 64 bajtów. Dyrektywa ''resb'' jest podobna do poznanej przed chwilą dyrektywy ''db'', tyle że tworzy konkretną ilość zmiennych bez przydzielania im wartości początkowych.
 
segment kod
Analogicznie do pierwszej linijki w naszym programie, tworzy segment o nazwie ''kod''. Poniżej znajduje się jego definicja.
 
..start:
Nazywa obecną pozycję słówkiem "start". Poprzedzenie ''start:'' dwoma kropkami oznacza, że chcemy aby to miejsce było początkiem naszego programu.
 
mov ax, dane
mov ds, ax
mov ax, stosik
mov ss, ax
Instrukcja [[../Instrukcje/Transferowe#mov|mov]] kopiuje wartość drugiego parametru do pierwszego. Jako, że po starcie programu, rejestry segmentowe są niezainicjowane, musimy ręcznie przydzielić im adresy odpowiednich segmentów. W pierwszej linijce kopiujemy adres segmentu ''dane'' do rejestru ax. Następnie z rejestru ax kopiujemy go do rejestru segmentowego ds (instrukcja mov nie pozwala na bezpośrednie przydzielanie wartości rejestrom segmentowym, dlatego musieliśmy użyć rejestru ax jako pośrednika). W następnych 2 linijkach powtarzamy operację, tyle że kopiujemy adres segmentu stosik (który jest stosem naszego programu) do rejestru ss.
 
mov dx, tekst
mov ah, 9
int 0x21
Ten fragment kodu zacznę tłumaczyć od końca. Instrukcja [[../Instrukcje/Różne#int|int]] wywołuje ''podprogram obsługi przerwania'' o podanym numerze (poprzedzenie go przedrostkiem 0x oznacza liczbę w zapisie szesnastkowym). Podprogram ów wywołuje odpowiednią funkcję o numerze podanym w rejestrze ah (wcześniej nadaliśmy temu rejestrowi wartość 9, więc instrukcja ''int 0x21'' wywołała funkcję numer 9 przerwania numer 21 w zapisie szesnastkowym). Wywołana w tym przypadku funkcja wyświetla w konsoli ciąg znaków, którego adres znajduje w rejestrze dx (przydzieliliśmy temu rejestrowi adres naszej zmiennej ''tekst''). W efekcie na ekranie pojawi się, więc napis ''Hello World!''
 
mov ax, 0x4C00
int 0x21
Wywołuje funkcję przerwania 21 o numerze 0x4C00. Odpowiada ona za zakończenie działania programu i oddanie sterowania do systemu.
 
end
Kończy proces asemblacji. Cokolwiek znajdzie się za tą dyrektywą zostanie zignorowane.
 
=== Goodbye world... ===