Jak powłoka wykonuje program?

11

Jeśli kompiluję program za pomocą gcc i próbuję go uruchomić z powłoki bash, jaka jest dokładna sekwencja kroków, po których następuje bash, aby go wykonać?

Wiem fork(), execve(), loader, dynamic linker(i inne rzeczy) są zaangażowane, ale może ktoś podać dokładną sekwencję kroków i trochę odpowiedniego odniesienia do czytania?

Edytować:

Z odpowiedzi wynika, że ​​pytanie może sugerować wiele możliwości. Chcę zawęzić do prostej sprawy:

(test.c po prostu drukuje hello world)

$ gcc test.c -o test
$ ./test

Jakie będą kroki w powyższym przypadku ( ./test), szczególnie związane z uruchomieniem programu bash w niektórych procesach potomnych, ładowaniem, łączeniem itp.?

Jake
źródło
4
Zapraszam do lwn.net/Articles/630727
cuonglm
3
Dlaczego nie spróbować „strace bash -c” test?
Sergiy Kolodyazhnyy
2
Wydaje się, że porządny podręcznik dotyczący systemów operacyjnych byłby dobrym źródłem informacji dla PO. Próba dowiedzenia się, jak działają systemy operacyjne poprzez zadawanie takich indywidualnych pytań, prawdopodobnie nie będzie procesem produkcyjnym.
Barmar
Przydałby
jinawee

Odpowiedzi:

5

Cóż, dokładna sekwencja może się różnić, ponieważ może istnieć alias powłoki lub funkcja, która najpierw zostanie rozwinięta / zinterpretowana przed uruchomieniem właściwego programu, a następnie różnice dla kwalifikowanej nazwy pliku ( /usr/libexec/foo) w porównaniu do czegoś, co będzie wyszukiwane we wszystkich katalogach o PATHzmiennej środowiskowej (tylko foo). Ponadto, szczegóły wykonania mogą skomplikować sprawy, ponieważ foo | bar | zotwymaga więcej pracy dla powłoki (niektóre liczby fork(2), dup(2)oraz, oczywiście, pipe(2)między innymi wywołań systemowych), podczas gdy coś exec foojest o wiele mniej pracy jako powłoka jedynie zastępuje się z nowy program (tzn. nie ma fork). Ważne są również grupy procesów (zwłaszcza grupa procesów pierwszego planu, z których wszystkie PID jedząSIGINTkiedy ktoś zaczyna mashowanie na Ctrl+ C, sesjach i czy zadanie będzie uruchamiane w tle, monitorowane ( foo &) czy w tle, ignorowane ( foo & disown). Szczegóły przekierowania we / wy również zmienią różne rzeczy, np. Jeśli standardowe wejście zostanie zamknięte przez powłokę ( foo <&-) lub czy plik zostanie otwarty jako stdin ( foo < blah).

stracelub podobnie będzie zawierać informacje na temat konkretnych wywołań systemowych wykonanych podczas tego procesu, i dla każdego z tych połączeń powinny znajdować się strony podręcznika man. Odpowiednim odczytem na poziomie systemu będzie dowolna liczba rozdziałów z „Zaawansowanego programowania w środowisku UNIX” Stevensa, podczas gdy książka powłoki (np. „Od powłoki do powłoki Z”) bardziej szczegółowo omawia stronę powłoki.

gałązka
źródło
Zredagowałem pytanie, aby zawęzić je do prostej sprawy
Jake,
1

Zakładając, że przykładowa powłoka z podręcznika (dla przejrzystości kodu), która jest już uruchomiona (więc dynamiczny linker jest gotowy), wspomniane polecenia będą wymagały od powłoki wykonania następujących wywołań systemowych:

  • czytaj: pobiera następne polecenie w tym przypadku gcc
  • widelec: potrzebne są dwa procesy, zakładamy, że rodzic zliczył 500, a dziecko do zilustrowania.
  • rodzic zadzwoni, czekając (501), tymczasem dziecko zadzwoni do exec. W tym momencie powłoka nie działa już na pid 501. gcc wykonuje wiele wywołań systemowych, w tym co najmniej otwieranie, zamykanie, czytanie, pisanie, chmod, fork, exec, wait i exit.
  • kiedy gcc wywoła polecenie exit, oczekiwanie powróci, zostanie wyświetlony komunikat write, aby wyświetlić monit, a proces się powtórzy.

Bardziej skomplikowane polecenia oczywiście dodają więcej komplikacji do tej podstawowej sekwencji. Dwa prostsze przykłady podstawowych komplikacji to podstawowe przekierowanie io, w którym między rozwidleniem a procesami exec i tła wstawiana jest sekwencja otwierania, zamykania i duplikacji, w której oczekiwanie jest pomijane (a do obsługi sigchld dodawane jest kolejne oczekiwanie).

Hildred
źródło
Mały dodatek: pytanie dotyczy ładowania i dynamicznego linkowania. Cały kod, który jest statycznie powiązany, tj. Faktycznie zawarty w pliku programu, jest wykonywany przez jądro przed uruchomieniem programu. Dynamicznie ładowane biblioteki, tj. Osobne pliki, są obsługiwane przez sam program przed uruchomieniem main (). Kod do tego jest automatycznie dodawany przez gcc.
Stig Hemmer