Pliki fs/binfmt_kodformatu.c

load_format_binary( struct linux_binprm *bprm, struct pt_regs *regs)

Funkcje ładujące program konkretnego formatu


Algorytm

Choć różne formaty w różny sposób odwzorowują w pamięci wykonywany program oraz udostępniają (lub nie) różne możliwości, to schemat algorytmu jest ten sam. Szkic został sporządzony na podstawie formatu ELF.

  1. Sprawdza pewne numery "magiczne" z pierwszych 128 bajtów pliku (bprm->buf) w celu rozpoznania, czy jest to plik tego formatu. Jeśli nie, zwraca -ENOEXEC.
  2. Czyta nagłówek pliku w celu ustalenia rozmieszczenia segmentów programu i potrzebnych bibliotek współdzielonych.
  3. Znajduje w pliku ścieżkę do interpretera i pobiera strukturę file dla niego, sprawdzając prawa wykonania (znów open_exec()).
  4. Ustawia pole personality procesu.
  5. Wykonuje pewne sprawdznia spójności interpretera i jego typu.
  6. Kopiuje do pamięci jądra argumenty programu i wywołuje flush_old_exec(), która to funkcja zwalnia zasoby starego programu:
    1. Zapewnia otrzymanie nowej struktury obsługi sygnałów, jeśli była współdzielona - make_private_signals(). Ustawia tablicę obsługi sygnałów na działanie domyślne - release_old_signals() oraz później wywołana flush_old_signals().
    2. Zwalnia wszystkie bloki stron i regiony pamięci należące do procesu - funkcja exec_mmap(). Pamięć procesu jest "wyczyszczona".
    3. flush_thread() i do_thread odpowiadają za wyczyszczenie wszelkich rejestrów.
    4. Zamyka wszelkie pliki z flagą close_on_exec - funkcja flush_old_files()

    To jest "punkt bez powrotu" - zmian nie da się już odwrócić.

  7. Odwzorowuje w pamięci "nowego" programu bloki stronicowe zawierające argumenty wywołania / zmienne środowiskowe i tworzy region stosu użytkownika - setup_arg_pages().
  8. Odwzorowuje kod i dane programu w pamięci procesu. Zostaną one sprowadzone z dysku do pamięci przy pierwszej próbie odwołania.
  9. Ładuje interpreter programu -load_format_interpreter(). Podzczas ładowania w pamięci procesu odwzorowuje się kod i dane programu interpretera.
  10. Ustala nowe uprawnienia procesu.
  11. Czyści flagę PF_FORKNOEXEC.
  12. Tworzy tablice z parametrami dla interpretera i zachowuje ją na stosie trybu użytkownika.
  13. Ustala adresy początków (i ew. końców) kodu, danych i stosu procesu - start_code, end_code, start_brk, end_brk, start_stack.
  14. Mapuje w pamięci procesu strony segmentu bss - set_brk()
  15. Makro start_thread ustawia rejestry wskaźników kodu i stosu na początek interpretera programu i wierzchołek stosu trybu użytkownika.
  16. Jeśli proces jest śledzony, wysyła do niego SIGTRAP.
  17. Zwraca 0 - sukces!.
Po powrocie do trybu użytkownika, proces zaczyna wykonywać kod interpretera. Pobiera on ze stosu dane przekazane w funkcji load_binary(). Odwzorowuje w pamięci procesu potrzebne biblioteki współdzielone. Po uaktualnieniu wszelkich informacji o odniesieniach i zapewnieniu spójności wykonuje skok do początku świeżo załadowanego programu i rozpoczyna jego wykonanie.