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

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») будет более подробно освещать аспекты оболочки.

thrig
источник
Я отредактировал вопрос, чтобы сузить до простого случая
Джейк
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).

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