2010-04-24 10 views
11

Mam poniższy kod, który otwiera plik, odczytuje go w buforze, a następnie zamyka plik.x86 Montaż: Przed wykonaniem System Call w systemie Linux należy zapisać wszystkie rejestry?

Zamknięcie systemowe systemu plików wymaga, aby numer deskryptora pliku znajdował się w rejestrze ebx. Rejestr ebx otrzymuje numer deskryptora pliku przed wykonaniem odczytu systemowego. Moje pytanie brzmi: czy powinienem zapisać rejestr ebx na stosie lub gdzieś przed wykonaniem wywołania systemowego odczytu, (czy mógłbym 80h wyrzucić do śmieci rejestr ebx?). A następnie przywrócić rejestr ebx do bliskiego wywołania systemowego? Czy jest to kod, który mam poniżej w porządku i bezpiecznie?

Uruchomiłem poniższy kod i działa, po prostu nie jestem pewien, czy jest to ogólnie uważane za dobrą praktykę montażową, czy nie, ponieważ nie zapisuję rejestru ebx przed wywołaniem odczytu 80h.

;; open up the input file 
mov eax,5  ; open file system call number 
mov ebx,[esp+8] ; null terminated string file name, first command line parameter 
mov ecx,0o  ; access type: O_RDONLY 
int 80h   ; file handle or negative error number put in eax 
test eax,eax 
js Error   ; test sign flag (SF) for negative number which signals error 

;; read in the full input file 
mov ebx,eax   ; assign input file descripter 
mov eax,3    ; read system call number 
mov ecx,InputBuff  ; buffer to read into 
mov edx,INPUT_BUFF_LEN ; total bytes to read 
int 80h 
test eax,eax 
js Error    ; if eax is negative then error 
jz Error    ; if no bytes were read then error 
add eax,InputBuff  ; add size of input to the begining of InputBuff location 
mov [InputEnd],eax  ; assign address of end of input 

;; close the input file 
;; file descripter is already in ebx 
mov eax,6  ; close file system call number 
int 80h   
+0

sugestia: Wykonaj jeden test, aby wynik odczytu był "<= 0" na szybkiej ścieżce, a następnie posortuj go w "Błąd". Zmniejsza to ilość pozycji historii przewidywania rozgałęzień, które normalnie potrzebuje twój kod. 'jle' zadziała, ponieważ' test eax, eax' czyści flagi przepełnienia i przenoszenia i ustawia SF i ZF zgodnie z wynikiem w taki sam sposób jak 'cmp eax, 0'. –

Odpowiedz

11

Rozmowa sama nie będzie uszkodzony niczego, oprócz umieszczenia wartości zwracanej w eaxint 80h. Więc fragment kodu, który masz, jest w porządku. (Ale jeśli twój fragment kodu jest częścią większej procedury, która ma być wywołana przez inny kod podążający za zwykłym ABI Linux x86, będziesz musiał zachować ebx i ewentualnie inne rejestry, przy wejściu do rutyny i przywrócić przy wyjściu .)

Właściwy kod w jądrze można znaleźć w arch/x86/kernel/entry_32.S. Trochę trudno jest go śledzić, ze względu na szerokie zastosowanie makr i różne szczegóły (obsługa śledzenia syscall, adnotacje debugowania DWARF, itp.), Ale: instrukcja obsługi int 80h to system_call (wiersz 493 w wersji, do której został podłączony); rejestry są zapisywane za pomocą makra SAVE_ALL (linia 497); i są przywracane ponownie przez RESTORE_REGS (linia 534) tuż przed powrotem.

+0

Ogólnie rzecz biorąc, zgodnie z 'syscall (2)', "niektóre architektury mogą bez przeszkód wymusić inne rejestry niewymienione tutaj". Konkretnie, wywołania systemowe x86-64 (wykonane za pomocą 'syscall') * do * clobber' rcx' i 'r11', zgodnie z moim odczytem [to writeup entry_64.S] (https://github.com/0xAX/ linux-insides/blob/master/SysCall/syscall-2.md). Jest to poparte faktem, że instrukcja 'sysret' (używana przez entry_64.S) ma' RIP = RCX' i 'RFLAGS = R11', a także pewne elementy segmentu. Powróciłeś do trybu użytkownika po jego wykonaniu. ** AFAICT, syscalls x86-64 zachowują wszystko oprócz R11, RCX i RAX **. –

+0

Nie mogłem znaleźć żadnej konkretnej dokumentacji, ani nawet komentarzy w kodzie, podając dokładną sytuację amd64 lub i386. Sądzę, że to dziwne, że tak ważny punkt, jak ten, pozostaje do odczytywania przez czytelników z dekodowania makr. Mam na myśli, że w praktyce to głównie implementatory libc, które potrzebują tych informacji, ale biorąc pod uwagę zaangażowanie Linuksa w utrzymywanie stabilnego ABI, nie spodziewam się, że to się kiedykolwiek zmieni. Więc można to zapisać. (I chyba tak, tutaj, więc przegłosowałem: P) –

+0

Update yes, 'syscall' yourself clobbers RCX/R11, i [Linux wywołania systemowe wykonane za pomocą' syscall' only clobber te + 'rax'] (https: // stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-on-i386-and-x86-6). Ale IIRC, to była moja edycja, która włączyła to; Nie pamiętam, czy kiedykolwiek znalazłem zewnętrzną dokumentację inną niż kod źródłowy Linuksa. –

Powiązane problemy