Asembler x86/Pierwszy program/NASM: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Lethern (dyskusja | edycje)
m nawigacja
poprawki
Linia 7:
====DOS/Windows====
<source lang="asm">
segment dane.data
tekst db "Hello World!",0Ah,0Dh,0Ah,"$"
 
segment stosik.s stack
resb 64
segment kod.text
 
mov ax, 0x4C00.data
segment kod
mov ahds, 9ax
..start:
mov ax, dane.s
mov dsss, ax
mov axdx, stosiktekst
mov ssah, ax9
int 0x2121h
mov dxax, tekst4C00h
int 0x2121h
mov ah, 9
int 0x21
mov ax, 0x4C00
int 0x21
end
</source>
Program ten po uruchomieniu w konsoli wyświetla na ekranie tekst "Hello World!". Postaram się zrozumiale wyjaśnić, o co w nim chodzi.
<source lang="asm">segment dane.data</source>
Oznacza, że od tego miejsca w dół definiowany jest nowy segment o nazwie "dane.data".
 
<source lang="asm">tekst db "Hello World!",0Ah,0Dh,"$"</source>
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 0A0D0D0A (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 $.
 
<source lang="asm">segment stosik.s stack</source>
Tworzy segment stosu (''stack'') o nazwie ''stosik.s'' i...
 
<source lang="asm">resb 64</source>
... 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.
 
<source lang="asm">segment kod.text</source>
Analogicznie do pierwszej linijki w naszym programie, tworzy segment o nazwie ''kod.text''. 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.
 
<source lang="asm">
mov ax, dane.data
mov ds, ax
mov ax, stosik.s
mov ss, ax
</source>
Linia 57 ⟶ 50:
mov dx, tekst
mov ah, 9
int 0x2121h
</source>
 
Ten fragment kodu zacznę tłumaczyć od końca. Instrukcja [[../Instrukcje/Różne#int|int]] wywołuje ''podprogram obsługi przerwania'' o podanym numerze (poprzedzeniezakończenie go przedrostkiemprzyrostkiem 0xh 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 0x2121h'' 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!''. </br>'''Uwaga''': należy zaznaczyć, że ''przerwanie 21h'' oraz opisana funkcja obsługiwane są przez MS-DOS, przez co kod nie jest przenośny na inne platformy nizniż Windows.
 
<source lang="asm">
mov ax, 0x4C004C00h
int 0x2121h
</source>
 
Wywołuje funkcję przerwania 21 o numerze 0x4C004C00h. Odpowiada ona za zakończenie działania programu i oddanie sterowania do systemu.
 
<source lang="asm">end</source>
Dyrektywa określająca koniec naszego kodu. Nie ma ona znaczenia i jest ignorowana, lecz tradycyjnie powinna stać na końcu pliku z kodem.
 
====Linux====
Linia 80 ⟶ 70:
 
segment .data
msg db '"Hello World!!',0x0a\n" ; umieszcza w segmencie danych ciąg znaków zakończony znakiem końca linii
 
segment .text
Linia 90 ⟶ 80:
mov ecx, msg ; adres pierwszego znaku do wyświetlenia
mov edx, 14 ; liczba znaków do wyświetlenia
int 0x8080h ; wywołanie funkcji systemowej wyświetlającej ciąg znaków o danej długości
 
; wyjscie z programu
mov eax, 1
movinc ebx, 5
int 0x80
; KONIEC PROGRAMU