Как оболочка выполняет программу?


11

Если я скомпилирую программу с использованием gcc и попытаюсь выполнить ее из оболочки bash, какова точная последовательность шагов, выполняемых bash для ее выполнения?

Я знаю fork(), execve(), loader, dynamic linker(и другие вещи) участвует, но может кто - то дать точную последовательность шагов , и некоторые подходящие ссылки для чтения?

Редактировать:

Судя по ответам, вопрос может предполагать множество возможностей. Я хочу сузить до простого случая:

(test.c просто печатает привет мир)

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

Каковы будут действия в приведенном выше случае ( ./test), конкретно относящиеся к программе запуска bash в каком-либо дочернем процессе, загрузке, компоновке и т. Д.?


4
Я приглашаю вас прочитать lwn.net/Article/630727
— cuonglm

3
Почему бы не попробовать `strace bash -c 'test'?
— Сергей Колодяжный

2
Похоже, достойный учебник по операционным системам был бы хорошим ресурсом для ОП. Попытка узнать, как работают операционные системы, задавая подобные вопросы, вряд ли будет продуктивным процессом.
— Бармар

Было бы полезно увидеть минимальный пример оболочки: brennan.io/2015/01/16/write-a-shell-in-c
— jinawee

Ответы:


5

Ну, точная последовательность может отличаться, так как может быть псевдоним оболочки или функция, которая сначала раскрывается / интерпретируется перед выполнением фактической программы, а затем различия для определенного имени файла ( /usr/libexec/foo) по сравнению с чем-то, что будет просматриваться во всех каталогах. из PATHпеременной окружения (только foo). Кроме того , детали исполнения могут осложнить ситуацию, поскольку foo | bar | zotтребует больше работы для оболочки (некоторое количество fork(2), dup(2)и, конечно же , pipe(2)среди других системных вызовов), в то время как что - то вроде exec fooгораздо меньше работы , как оболочка просто заменяет себя новая программа (то есть, это не так fork). Также важны группы процессов (особенно группа процессов переднего плана, все PID которыхSIGINTкогда кто-то начинает затираться в Ctrl+ C, сессиях, и будет ли задание выполняться в фоновом режиме, monitored ( foo &) или background, ignored ( foo & disown). Детали перенаправления ввода / вывода также изменят ситуацию, например, если стандартный ввод закрывается shell ( foo <&-), или файл открывается как stdin ( foo < blah).

straceили подобное будет информативным о конкретных системных вызовах, выполняемых в ходе этого процесса, и для каждого из этих вызовов должны быть страницы руководства. Подходящим чтением на уровне системы будет любое количество глав из «Расширенного программирования в среде UNIX» Стивенса, в то время как книга оболочек (например, «От Bash до Z Shell») будет более подробно освещать аспекты оболочки.


Я отредактировал вопрос, чтобы сузить до простого случая
— Джейк

1

Предполагая, что оболочка примера учебника (для ясности кода) уже запущена (так что динамический компоновщик сделан), команды, которые вы упомянули, потребуют, чтобы оболочка сделала следующие системные вызовы:

  • read: получает следующую команду в этом случае gcc
  • fork: нужны два процесса, мы предполагаем, что у родителя есть pid 500, а у потомка - для иллюстрации.
  • родитель вызовет wait (501), а ребенок вызовет exec. На этом этапе оболочка больше не работает на pid 501. gcc выполняет множество системных вызовов, включая как минимум open, close, read, write, chmod, fork, exec, wait и exit.
  • когда gcc вызывает exit, возвращается wait, вызывается write для отображения приглашения, и процесс повторяется.

Более сложные команды, конечно, добавляют больше сложности к этой основной последовательности. Двумя более простыми примерами основных усложнений являются перенаправление базового ввода-вывода, когда между ветвью и exec и фоновыми процессами вставляется открывающая, закрывающая, дублирующая последовательность, где ожидание пропускается (и еще одно ожидание добавляется в обработчик sigchld).


Небольшое дополнение: вопрос о загрузке и динамической компоновке. Весь код, который статически связан, то есть фактически включен в файл программы, выполняется ядром до запуска программы. Динамически загружаемые библиотеки, т.е. отдельные файлы, обрабатываются самой программой перед запуском main (). Код для этого автоматически добавляется gcc.
— Стиг Хеммер

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.