Powrót do strony głównej exec

Ładowanie plików w formacie ELF - procedura do_load_elf_binary

        Plik w formacie ELF podzielony jest na sekcje - każda sekcja ma swoją wielkość w pliku, docelową wielkość w pamięci, adres początkowy itp. Informacje te przechowywane są w nagłówku sekcji.Plik ELF zawiera więc krótki nagłówek nadrzędny, zawierający m. in. oznaczenie maszyny docelowej oraz liczbę sekcji, a po nim następują nagłówki poszczególnych kawałków. Każdy z nich zawiera położenie odp. sekcji w pliku. Nagłówek jednej z sekcji może wskazywać na konieczność załadowania interpretatora ELF.
       Pierwszą akcją procedury jest sprawdzienie, czy badany plik jest rzeczywiście typu ELF, oraz czy jest wykonywalny. Następnie sprawdzamy, czy kod programu jest przeznaczony dla naszej maszyny - elf_check_arch(elf_ex.e_machine)). Następnie sprawdzamy, czy system plików umożliwia stronicowanie zbiorów - do umieszczania programu w pamięci używać będziemy do_mmap. Później wczytujemy nagłówki wszystkich sekcji do pam. jądra. Następnie przeglądamy załadowane informacje ustalając nazwę interpretatora, jeśli jest konieczny (tylko jedna sekcja może podawać konieczność wczytania interpretatora - w przeciwnym przypadku zwracamy błąd). Następnie sprawdzamy, czy interpretator jest biblioteką typu ELF, czy a.out i jeśli w tym drugim przypadku dodajemy deskryptor otwartego pliku ELF jako parametr wywołania interpretatora (?!). Dalej już następuje "punkt bez wyjścia" - usuwamy kontekst starego programu (flush_old_exec). Teraz ponownie przebiegamy wszystkie nagłówki, aby ustalić rozmiar pamięci potrzebny na dane nieinicjowane wszystkich sekcji pliku mających atrybut PT_LOAD, oraz odwozorowujemy odpowiednie fragmenty pliku do pamięci wirualnej (do_mmap). Teraz ładujemy bibliotekę interpretującą, jeśli jest to konieczne. W tym celu wywołujemy load_elf_interpreter lub load_aout_interpreter. Procedury te zawierają zdublowany kod funkcji "do_load_elf_library" i "do_load_aout_library". Do zabicia procesu w razie niepowodzenia już po wywołaniu flush_old_exec używamy sygnału SIGSEGV (!?). Jeśli używany interpretator nie jest /usr/lib/libc.so.1 ani /usr/lib/ld.so.1, to personality procesu ustawiamy na PER_SVR4. Uaktualniamy licznik instancji domeny wykonywania i formatu odp. starego i nowego procesu. Podobnie, jak przy ładowaniu plików a.out przerabiamy teraz parametry wywołonia i środowisko na tablice (char*) w pamięci procesu (create_elf_tables). Teraz już przydzielamy dodatkową pamięć na zmienne nieinicjowane wartościami z pliku i zerujemy ją (padzero) Jeśli proces jest typu PER_SVR4, to ustawiamy zerową stronę jako tylko do odczytu. Następnie uruchamiamy już nowy proces (start_thread) i blokujemy go, jeśli ma podlegać śledzeniu (pracy krokowej).


Wczytywanie biblioteki dzielonej typu ELF - procedura do_load_elf_library

        Kod tej procedury pokrywa się w dużej mierze z do_load_elf_binary. Biblioteka może jednak zawierać co najwyżej dwie sekcje, z których tylko jedna może być typu PT_LOAD. Wyszukujemy tę sekcję i odwzorowujemy ją do pamięci wirtualnej. Następnie zerujemy "końcówkę" ostatniej strony przydzielonej na kod i dane inicjowane wartościami z pliku (padzero). Teraz już tylko pozostaje przydzielić pamięć na dane nieinicjowane.

        Pozostałą część pliku binfmt_elf.c stanwi kod związany z wykonywaniem "core dump" - zrzutu pamięci procesu na dysk. Ze względu na brak związku z algorytmem exec, nie opisujemy tej części.



Opracowanie:
Marcin Mędelski-Guz
Komentarze w pliku binfmt_elf.c: Marcin Mędelski-Guz i Sławomir Poreda.