A.D.Danilecki, Poznan, Polska
Politechnika Poznanska, Wydzial Informatyki i Zarzadzania
W tej chwili adanilecki _malpa_ cs.put.poznan.pl
Z wykorzystaniem wielu listow z uwagami od wielu autorow
Krótki wstęp do programowania z wykorzystaniem inline assemblera x86


3. Punkt drugi : Zasady ogólne



Warning: include(navigator_up.php?name=) [function.include]: failed to open stream: No such file or directory in /home/adanilecki/htdocs/inline_asm/punkt2.php on line 22

Warning: include() [function.include]: Failed opening 'navigator_up.php?name=' for inclusion (include_path='.:/home/spsk/nowy_porrtal/PEAR/:/usr/share/php:/usr/share/php5:/usr/share/php/smarty/:/home/spsk/nowy_porrtal/mgr/library/') in /home/adanilecki/htdocs/inline_asm/punkt2.php on line 22

Jeżeli w środku programu w C chcemy umieścić kod w assemblerze, powinniśmy stosować jedną z dwóch składni : pierwszą, prostą :
asm ( " instrukcje assemblerowe " )
lub drugą, rozszerzoną (ang. extended asm) :
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.