= Makra =
== Wstęp ==
Nasm zawiera preprocesor, który pozwala ułatwić sobie pisanie kodu w wielu
sytuacjach. Należy jednakże pamiętać, że użycie makr może zaciemnić kod i
spowodować ukrycie użycia rejestrów i spowodować błędy, więc należy ich
używać ostrożnie i w sposób przemyślany.

Dyrektywy preprocesora Nasm zaczynają się od znaku %

== Dyrektywa define ==
Dyrektywa define to czysto tekstowe podstawienie zadanego tekstu w miejscu
użycia.

Składnia definicji:
%define nazwa tekst

Składnia wywołania:
nazwa

Przykład:
%define nl call nowa_linia 	; definicja
nl				; wywołanie

Dłuższy tekst można zawinąć dodając na końcu linii znak "\", np:
%define nl call \
      nowa_linia

Dyrektywa define jest czuła na wielkość liter, czyli np. słowo NL by nie
zostało rozwinięte do nowa_linia. Żeby zadeklarować makro które działa
niezależnie od wielkości liter należy użyć dyrektywy idefine.

Dyrektywy define są rozwijane w miejscu wywołania, np.
%define exit_label ok
%define label exit_label
%define exit_label blad
jmp label
Powoduje skok do etykiety "blad", a nie "ok".

Można zadeklarować makro, które rozwija się w miejscu definicji, a nie
wywołania za pomocą dyrektywy xdefine. Np.
%define exit_label ok
%xdefine label exit_label
%define exit_label blad
jmp label
Powoduje skok do etykiety "ok", a nie "blad".


== Dyrektywy define z argumentami ==
Dyrektywa define może mieć argumenty, które zostaną tekstowo podstawione w
momencie wywołania.

Składnia definicji:
%define nazwa(param1, param2) tekst z użyciem param1 i param2

Składnia wywołania:
nazwa(wartość1, wartość2)

Przykład:
%define param(i) [ebp+4*i]
mov eax, param(0)               ; argc

Nazwa makra jest przeciążana, więc można mieć różne wersje dla różnej liczby
argumentów, ale nie można wtedy przedefiniować gołej nazwy, bez parametrów!

== Dyrektywa undef ==
Dyrektywa undef służy do usunięcia definicji makra. 
Składnia:
%undef nazwa

== Dyrektywa %strlen ==
Dyrektywa strlen zwraca długość napisu jako liczbę (stałą).
Składnia:
%strlen nazwa tekst

Przykład:
%define s_tekst 'Hello world'
%strlen dlugosc_tekstu s_tekst

== Dyrektywa macro ==
Dyrektywa macro tworzy wielolinijkowe makro, podobne do dyrektywy c #define, 
które może być używane do generowania powtarzalnego kodu i funkcji inline.

Składnia definicji:
%macro nazwa liczba_parametrow
; kod używający parametrów %1 do %liczba_parametrow
%endmacro

Składnia wywołania:
nazwa parametr1, parametr2

Przykład:
%macro exit 1
        mov ebx, %1
        mov eax, 1
        int 80h
%endmacro

exit 7		; wywołanie

== Etykiety lokalne w makrze ==
W makrach stworzonych za pomocą dyrektywy macro można używać etykiet, ale
żeby były one niepowtarzalne w programie (np. żeby można było etykiety
"koniec" użyć w różnych makrach) trzeba ją zadeklarować jako lokalną dla
makra stosując dwa znaki % przed nazwą, np.:
%%koniec:
...
	jmp %%koniec

== Dyrektywa rep ==
Dyrektywa rep pozwala powtórzyć dany kod określoną liczbę razy.
Składnia:
%rep liczba_powtorzen
....kod
%endrep

Przykład:
%rep 10
	add eax, eax
%endrep

== Kod warunkowy ==
Dyrektywa %if pozwala warunkowo skompilować kod, w zależności od wartości
warunku (warunek jest liczbą, jest prawdziwy jeśli nie jest równy zero,
można używać znaków <,>,=,>=, itd.).
Składnia:
%if warunek
..kod
%elif warunek
... kod
%else
... kod
%endif

Przykład:
%if liczba = 1
inc eax
%else
add eax, liczba
%endif

Dyrektywa ifdef pozwala sprawdzać, czy jest zdefiniowane makro za pomocą
jednej z dyrektyw define, np.
%ifdef mnoz
%undef mnoz
%endif
Można go używać podobnie jak dyrektywy #ifdef w języku C.

== Dołączanie plików ==
Dyrektywa include pozwala dołączyć kod z pliku do przetwarzanego właśnie
pliku, podobnie jak #include w C.
Składnia:
%include "nazwa_pliku"
np.
%include "moja_biblioteka_asm.inc"

Żeby ustrzec się przed błędami gdy dołączymy plik wiele razy do programu w
asemblerze, można zastosować konstrukcję znaną z plików nagłówkowych C:
%ifndef jakis_identyfikator
%define jakis_identyfikator
..kod biblioteki
%endif

Literatura:
- nasmdoc4.html z dokumentacji NASM

Zadania:
- Zamienić funkcję "wypisz" na makro, któremu jako argument podaje się nazwy
rejestrów, w których jest adres i długość napisu.
- Zaimplementować operację xor na rejestrach mmx jako makro, któremu podaje
się adres pamięci i długość.
- Zamienić funkcję wypisz_liczbe na makro.
- Napisać bibliotekę makr, które ułatwiają tworzenie funkcji asemblerowych
w konwencji języka C, tzn. zawierającą makra implementujące protokół
wejścia do funkcji, protokół wyjścia z funkcji, zwracanie n-tego parametru,
odwołanie do n-tej zmiennej lokalnej.
