Witam i o drogę pytam.
Wziąłem źródła Linuksa 0.01.
(Chciałem zacząć od o wiele prostszych
rzeczy niż Linux 2.4.x, w 2.x.y się gubię).
A więc wziąłem ten kod i zacząłem czytać.
Asemblera jakoś kapuje, C też.
Ja bym kupił książkę, Mikom wydał kiedyś "Linux kernel. Jądro systemu"
Ale czy, ktoś mógł by mi opowiedzieć
coś, nie coś o składni __asm__.
Przykład (z linux/mm/mm.c):
#define copy_page(from,to) \
__asm__("cld ; rep ; movsl"::"S" (from),"D" (to),"c" (1024):"cx","di","si")
Zapewne wystarczy przerobienie mi
tego przykładu na czysty asembler
(no może z niewielkimi komentarzami do:
dwukropków;
S, D, c - co to;
cx, di i si - po co to na końcu).
To jest czysty asembler :-). Najprościej będzie rozbić to na kilka linijek:
__asm__(
"cld ; rep ; movsl"
:
:"S" (from),"D" (to),"c" (1024)
:"cx","di","si")
Piszę o liniach, choć są to pola pooddzielana dwukropkami. Jednak po
rozbiciu tego na linie IMHO zapis jest bardziej czytelny, i tej notacji
będę się trzymał.
Pierwsza linia zawiera łańcuch z mnemonikami instrukcji. Zwykle jest
to wiele linii (jeśli masz dłuższy kawałek kodu).
Druga (w tym wypadku pusta) zawiera opisy danych wyjściowych tego
bloku. Po skończeniu jego wykonywania kompilator wstawi kod,
przepisujący dane z rejestrów do odpowiednich zmiennych.
Trzeci linia zawiera opis danych wejściowych. Analogicznie jak
w drugiej, przed wykonaniem kodu kampilator przepisze zawartości
zmiennych do wskazanych rejestrów.
Format drugiej i trzeciej linii jest taki sam. W czydzysłowach
zawarty jest kod rejestru (a dla ax, b dla bx, c dla cx, d dla dx,
S dla si i D dla di. Nie pamiętam symbolu dla bp i sp). W nawiasach
następujących po kodzie rejestru występuje nazwa zmiennej, której
wartość chcesz przesłać do/z tego rejestru. Nie jest konieczne
zapisywanie bitowości rejestru - kompilator sam ją określi. Po
przecinku podajemy następne zmienne, z wartości któeych chcemy
skorzystać we wstawce.
W czwartej linii wskazujesz rejstry, których używał Twój kod.
Dzięki temu mówisz kompilatorowi, czego zawartość zmieniłeś, a on
w razie potrzeby zachowuje i odtwarza ich wartości. Dzięki temu
unikasz stosowania par push/pop, pozwalając kompilatorowi zdecydować,
gdzie ochrona zawartości rejestru jest konieczna, a gdzie można
ją opuścić bez żadnej szkody dla programu.
UWAGA! Ponieważ dawno nie korzystałem z wstawek asemblerowych
w gcc (ostatnim razem był to kod MMX jeszcze pod DOS w DJGPP - łezka
się w oku kręci :-) ), informacje podane w akapicie o formacie
linii drugiej i trzeciej mogą byc nieaktualne lub nie do końca zgodne
z rzeczywistością. Mam jednak nadzieję, że niczego nie pokręciłem,
i że rozjaśniłem trochę składnię wstawek __asm__.
Pozdrawiam.