asm ("instrukcje..."
-
: Zmienne "wyjściowe"
: Wartości "wejściosciowe"
: Lista zmodyfikowanych rejestrów/pamięci
)
W najprostszej postaci nasz pierwszy program w assemblerze może wyglądać tak:
void main()
{
asm(" nop ");
}
Program ten nic nie robi. jego działanie sprowadza się do wykonania instrukcji
assemblerowej nop która jest odpowiednikiem instrukcji pustej w C,
czyli nie powoduje wykonania żadnej akcji.
Teraz kilka zasad ogólnych:
Używamy tzw. składni AT&T, która jest standardem w świecie UNIXA i
różni się dość sporo od składni intelowskiej. Jeżeli wolisz składnię intela,
musisz ściągnąć nasma i
programować osobne programy w assemblerze a nie tylko wstawki. GCC standardowo wypluwa kod w formacie AT&T, jednakze mozna pisac wstawki w skladni intelowskiej (patrz punkt Skladnia intelowska w gcc )
Jeżeli używamy postaci prostej instrukcji assemblerowej (ang. assembler statement),
to nazwy rejestrów poprzedzamy zawsze znakiem '%'. W postaci rozszerzonej nazwy
rejestrów poprzedzamy zawsze dwoma znakami '%', czyli piszemy : %eax, %ecx.. w postaci
prostej i %%eax, %%ecx.. w postaci rozszerzonej. Skąd to się bierze, wyjaśni się
wkrótce.
Stałe (immediate value) zaznaczamy przedrostkiem '$', czyli piszemy:
np. mov $1, %eax
Każdą prawie komendę można zapisać z przyrostkiem określającym typ argumentu,
dopuszczalne przyrostki to 'b' (byte) 'w' (word) i 'l' (long). Jeżeli przyrostek pominiemy,
gcc będzie zgadywać za nas typ operandu i może zgadnąć źle.
porządek operandów zawsze jest'źródło', 'przeznaczenie' , czyli jeśli chcemy
wpisać liczbę jeden do rejestru eax piszemy, jak wyżej :
movb $1,%eax
czyli nieco inaczej niż w klasycznym assemblerze znanym
z DOS-a.
Jeżeli chcemy operować na adresie zmiennej, piszemy $zmienna, jeżeli na jej zawartości,
piszemy zmienna. Zmienna musi być globalna w programie w C. Jeżeli np zadeklarowaliśmy
globalną zmienną int a, to nastepujące instrukcje
mają następujący efekt :
asm ("mov $1,a") ; // a=1;
Jeżeli adres zmiennej ładujemy do rejestru, to możemy się do zawartości
zmiennej odwoływać za pomocą nawiasów, np
asm( "mov $a,%eax\n" "mov $1,(%eax)");// a=1
Hej! co to za '\n'? Otóż jeśli używamy kilku intrukcji assemblera w ten sposób
właśnie się je oddziela. Ten znak '\n' to znak końca linii.
Teraz jak operować na wskaźnikach?
kod w c: *(p+1) w asmie 1(%eax) zakładając że w %eax znajduje
się adres zmiennej p.
Zasady te znajdziesz w plikach ,,info'' do as-a i gcc. Szukaj info as->
Machine Dependencies->i386. Oraz info gcc->C Extensions->Extended Asm. Także
info gcc->Machine Desc->Constraints->Machine Constraints.
To byłoby tyle jeśli chodzi o ogólne zasady. Teraz przejdziemy do pisania
krótkich programików z wykorzystaniem składni rozszerzonej.