Asembler x86/Pierwszy program/GNU AS
Hello world! (POSIX)
edytujOto przykład programu, napisanego w asemblerze GNU, wyświetlającego napis "Hello World!" w systemie zgodnym z normą POSIX, uruchomionym na komputerze typu i386:
.text
.global _start
_start:
movl $4, %eax
movl $1, %ebx
movl $napis, %ecx
movl $len, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
.data
napis:
.string "hello world!\n"
len = . - napis
Aby skompilować powyższy program musisz wydać następujące polecenia. Najpierw trzeba kod zasemblować aby uzyskać plik obiektowy *.o:
as hello.s -o hello.o
Tak otrzymany kod wynikowy, musisz poddać działaniu linkera ld:
ld hello.o -o hello
Teraz dopiero program jest wykonywalny. Możesz go uruchomić w konsoli wydając polecenie w katalogu w którym jest program:
./hello
Omówię teraz po kolei kod tego programu:
.text .global _start
Ten fragment informuje asembler, że informacje tutaj zawarte są kodem programu, a etykieta _start ma być etykietą globalną (umożliwi to m.in. wykorzystanie tej etykiety jako głównej funkcji programu).
_start:
"Zawartość" etykiety _start.
movl $4, %eax
movl $1, %ebx
movl $napis, %ecx
movl $len, %edx
int $0x80
Instrukcja mov (l na końcu to informacja, że zapisujemy dane do 32-bitowego rejestru) przenosi dane do odpowiednich rejestrów - w EAX znajdzie się numer funkcji systemowej (4 - write), EBX - plik docelowy (1 - standardowe wyjście), w ECX - adres, pod którym znajdują się dane do wyświetlenia oraz EDX - długość napisu. Instrukcja int powoduje wywołanie przerwania i realizację przez system operacyjny odpowiedniej czynności - w tym przypadku wypisanie na ekran "Hello world!".
movl $1, %eax
movl $0, %ebx
int $0x80
Tym razem wywołamy funkcję exit, której argumentem będzie 0. W ten sposób "poprosimy" system operacyjny o zakończenie pracy programu.
.data
Oznacza, że dalsza część programu będą stanowiły dane, potrzebne do wykonania instrukcji.
napis:
Nie używamy .globl - etykieta napis ma być widoczna tylko dla kodu programu i nie jest istotna w procesie tworzenia pliku wykonywalnego.
.string "hello world!\n"
Tworzymy napis, który będzie widoczny pod adresem etykiety "napis".
len = . - napis
Jest to zmienna, która zawiera długość napisu. Kropka oznacza "aktualny adres" w pamięci (w naszym przypadku koniec napisu), a "napis" - adres etykiety, pod którą zawarto początek napisu. Różnica koniec - początek daje długość napisu, która jest niezbędna, aby program wypisał na ekranie dokładnie tyle znaków, ile liczy sobie napis.
Hello World! (wersja DOS)
edytujAnalogiczny program, który kompiluje się pod systemem DOS(będąc emulowanym pod Windowsem) mógłby wyglądać np. tak:
.data
napis:
.string "Hello World!\n$"
.text
.globl _start
_start:
movw $napis, %dx
movb $9, %ah
int $0x21
movw $0x4C00, %ax
int $0x21
Przyglądając się składni GNU możesz zauważyć, jak bardzo różni się ona od składni NASM lub MASM.