2011-08-01 27 views
5

Potrzebuję jakiegoś odniesienia, ale dobrego, być może z kilkoma ładnymi przykładami. Potrzebuję go, ponieważ zaczynam pisać kod w zespole za pomocą asemblera NASM. Mam to odniesienie:Dobre referencje dla syscalls

http://bluemaster.iu.hio.no/edu/dark/lin-asm/syscalls.html

co jest dość ładne i użyteczne, ale ma wiele ograniczeń, ponieważ nie wyjaśnia pól w innych rejestrach. Na przykład, jeśli używam zapisu syscall, wiem, że powinienem umieścić 1 w rejestrze EAX, a ECX jest prawdopodobnie wskaźnikiem do łańcucha, ale co z EBX i EDX? Chciałbym też wyjaśnić, że EBX określa dane wejściowe (0 dla stdin, 1 dla czegoś innego itd.), A EDX to długość wprowadzanego łańcucha itp. Itd. Mam nadzieję, że zrozumiałeś, czego chcę , Nie mogłem znaleźć takich materiałów, dlatego właśnie tutaj piszę. Z góry dzięki.

Odpowiedz

0

Jeśli pobierzesz tę stronę internetową (jak sugeruje w drugim akapicie) i pobierzesz źródła jądra, możesz kliknąć łącza w kolumnie "Źródło" i przejść bezpośrednio do pliku źródłowego, który implementuje wywołania systemowe. Możesz odczytać ich sygnatury C, aby zobaczyć, do czego służy dany parametr.

Jeśli szukasz tylko szybkiego odniesienia, każde z tych wywołań systemowych ma interfejs biblioteki C o tej samej nazwie, minus sys_. Tak więc, na przykład, można sprawdzić man 2 lseek, aby uzyskać informacje na temat parametrów dla sys_lseek:

off_t lseek(int fd, off_t offset, int whence); 

gdzie, jak widać, parametry dopasować te z tabeli HTML:

%ebx   %ecx %edx 
unsigned int off_t unsigned int 
+0

Oczywiście, nawet jeśli wyszukujesz każdego z nich w google lub wyszukiwaniu kodu źródłowego w celu jego implementacji, możesz znaleźć bezpośrednie przykłady, jak są one używane - co zrobiłem. Celem mojego wpisu jest pominięcie wyszukiwania i analizy za pomocą miłego arkusza oszukańczego. Dzięki. –

11

Standardowym językiem programowania w systemie Linux jest C. Z tego względu najlepsze opisy wywołań systemowych pokażą je jako wywoływane funkcje C. Biorąc pod uwagę ich opis jako funkcję C i wiedzę o tym, jak zmapować je do rzeczywistego wywołania systemowego w złożeniu, będzie można łatwo użyć dowolnego wywołania systemowego, które chcesz.

Po pierwsze, potrzebujesz referencji dla wszystkich wywołań systemowych, jakie będą wyglądały dla programisty C. Najlepszą, jaką znam, jest sekcja Linux man-pages project, w szczególności sekcja system calls.

Jako przykład przyjrzyjmy się wywołaniu systemowemu write, ponieważ jest to odpowiedź na pytanie. Jak widać, pierwszym parametrem jest liczba całkowita ze znakiem, która zwykle jest deskryptorem pliku zwróconym przez systemową konfigurację open. Te deskryptory plików mogły również zostać odziedziczone po procesie nadrzędnym, jak to zwykle bywa w przypadku pierwszych trzech deskryptorów plików (0 = stdin, 1 = standardowe wyjście, 2 = stderr). Drugi parametr to wskaźnik do bufora, a trzeci parametr to rozmiar bufora (jako liczba całkowita bez znaku). Wreszcie funkcja zwraca liczbę całkowitą ze znakiem, która jest liczbą zapisanych bajtów lub liczbą ujemną z powodu błędu.

Teraz, jak odwzorować to na faktyczne wywołanie systemowe? Istnieje wiele sposobów wykonania wywołania systemowego na 32-bitowym systemie x86 (z którego prawdopodobnie korzystasz, na podstawie nazw rejestrów); uważaj, że jest zupełnie inny na 64-bitowym x86 (upewnij się, że montujesz w trybie 32-bitowym i łączymy 32-bitowy plik wykonywalny, zobacz przykład, jak coś może pójść źle w przeciwnym razie). Najstarszym, najprostszym i najwolniejszym z nich w 32-bitowym x86 jest metoda int $0x80.

Dla metody int $0x80, można umieścić numer wywołania systemowego w %eax i parametry w %ebx, %ecx, %edx, %esi, %edi i %ebp, w tej kolejności. Następnie wywołujemy int $0x80, a zwracana wartość z wywołania systemowego jest na %eax. Zwróć uwagę, że ta wartość zwracana to inna z tego, co mówi odnośnik; odniesienie pokazuje, jak biblioteka C go zwróci, ale wywołanie systemowe zwraca -errno po błędzie (na przykład -EINVAL). Biblioteka C przeniesie to do errno i zwróci -1 w takim przypadku. Aby uzyskać więcej szczegółów, zobacz syscalls(2) i intro(2).

więc, w przykładzie write, należy umieścić numer systemowy write zaproszenia w %eax pierwszy parametr (numer deskryptora pliku) w %ebx, drugi parametr (wskaźnik do łańcucha) w %ecx, a trzeci parametr (długość struny) w %edx. Wywołanie systemowe zwróci w postaci %eax albo liczbę zapisanych bajtów albo zanegowany numer błędu (jeśli wartość zwracana wynosi od -1 do -4095, jest to zanegowany numer błędu).

Na koniec, jak znaleźć numery połączeń systemowych? Można je znaleźć pod adresem /usr/include/linux/unistd.h. W moim systemie obejmuje to tylko /usr/include/asm/unistd.h, który ostatecznie obejmuje /usr/include/asm/unistd_32.h, więc numery są tam (dla write, można zobaczyć __NR_write jest 4). To samo dotyczy numerów błędów, które pochodzą z /usr/include/linux/errno.h (w moim systemie, po ściganiu łańcucha włączenia znajduję pierwsze z /usr/include/asm-generic/errno-base.h, a resztę pod /usr/include/asm-generic/errno.h). W przypadku wywołań systemowych, które używają innych stałych lub struktur, ich dokumentacja mówi, które nagłówki należy szukać, aby znaleźć odpowiednie definicje.

Teraz, jak już powiedziałem, int $0x80 jest najstarszą i najwolniejszą metodą. Nowsze procesory mają specjalne instrukcje systemowe, które są szybsze. Aby z nich korzystać, jądro udostępnia wirtualny dynamiczny obiekt współdzielony (vDSO, jest podobny do biblioteki współdzielonej, ale tylko w pamięci) z funkcją, którą można wywołać w celu wykonania wywołania systemowego przy użyciu najlepszej dostępnej metody dla danego sprzętu. Udostępnia także funkcje specjalne, aby uzyskać bieżący czas, bez konieczności wykonywania połączenia systemowego i kilku innych rzeczy. Oczywiście korzystanie z dynamicznego linkera jest nieco trudniejsze.

Istnieje również inna starsza metoda, vsyscall, która jest podobna do vDSO, ale korzysta z pojedynczej strony o stałym adresie. Ta metoda jest przestarzała, spowoduje ostrzeżenia w dzienniku systemowym, jeśli używasz najnowszych jąder, może być wyłączona podczas uruchamiania na nowszych jądrach i może zostać usunięta w przyszłości. Nie używaj tego.

+0

To jedna z najlepszych odpowiedzi, jakie kiedykolwiek widziałem. –