Ключевые вопросы
Лекция № 6. Загрузка программ. Часть 1
Продолжительность: 2 часа (90 мин.)
· Основные понятия и определения: операционная система (ОС), программное обеспечение (ПО), системное программное обеспечение.
· Создание процессов в UNIX
· Абсолютная загрузка
· Разделы памяти
13.2.1 Общие сведения — до 15 мин.
Выяснив, что представляет собой программа, давайте рассмотрим процедуру ее загрузки в оперативную память компьютера (многие из обсуждаемых далее концепций, впрочем, в известной мере применимы и к прошивке программы в ПЗУ).
Для начала предположим, что программа была заранее собрана в некий единый самодостаточный объект, называемый загрузочным или загружаемым модулем. В ряде операционных систем программа собирается в момент загрузки из большого числа отдельных модулей, содержащих ссылки друг на друга, но об этом ниже.
Для того чтобы не путаться, давайте будем называть программой ту часть загрузочного модуля, которая содержит исполняемый код. Результат загрузки программы в память будем называть процессом или, если нам надо отличать загруженную программу от процесса ее исполнения, образом процесса. К образу процесса иногда причисляют не только код и данные процесса (подвергнутые преобразованию как в процессе загрузки, так и в процессе работы программы), но и системные структуры данных, связанные с этим процессом. В старой литературе процесс часто называют задачей.
|
|
В системах с виртуальной памятью каждому процессу обычно выделяется свое адресное пространство, поэтому мы иногда будем употреблять термин процесс и в этом смысле. Впрочем, во многих системах значительная часть адресных пространств разных процессов перекрывается — это используется для реализации разделяемого кода и данных.
В рамках одного процесса может исполняться один или несколько потоков или нитей управления. Это понятие будет подробнее разбираться в главе 8.
Некоторые системы предоставляют и более крупные структурные единицы, чем процесс. Например, в системах семейства Unix существуют группы процессов, которые используются для реализации логического объединения процессов в задания (job).
Ряд систем имеют также понятие сессии — совокупности всех заданий, которые пользователь запустил в рамках одного сеанса работы. Впрочем, соответствующие концепции часто плохо определены, а их смысл сильно меняется от одной ОС к другой, поэтому мы практически не будем обсуждать эти понятия.
В более старых системах и в старой литературе называют результат загрузки задачей, а процессами — отдельные нити управления.
|
|
Однако в наиболее распространенных ныне ОС семейств Unix и Win32, принято задачу называть процессом, а процесс — нитью (tread).
Этой терминологии мы и будем придерживаться, кроме тех случаев, когда будем обсуждать примеры из жизни ОС, в которой принята иная терминология.
13.2.2 Создание процессов в UNIX — до 15 мин.
В системах семейства Unix новые процессы создаются системным вызовом fork. Этот вызов создает два процесса, образы которых в первый момент полностью идентичны, у них различается только значение, возвращенное вызовом fork. Типичная программа, использующая этот вызов, выглядит так, как представлено в примере 3.1.
При этом каждый из процессов имеет свою копию всех локальных и статических переменных. На процессорах со страничным диспетчером памяти физического копирования не происходит. Изначально оба процесса используют одни и те же страницы памяти, а дублируются только те из них, которые были изменены. На системах, не имеющих страничного или сегментного диспетчера памяти, fork требует копирования адресных пространств, что приводит к большим накладным расходам, да и просто не всегда возможно.
Если мы хотим запустить другую программу, то мы должны исполнить системный вызов из семейства exec. Вызовы этого семейства различаются только способом передачи параметров. Все они прекращают исполнение текущего образа процесса и создают новый процесс с новым виртуальным адресным пространством, но с тем же идентификатором процесса. При этом у нового процесса будет тот же приоритет, будут открыты те же файлы (это часто используется), и он унаследует ряд других важных характеристик.
Несколько неожиданное, но тем не менее верное описание действия exec — это замена образа процесса в рамках того же самого процесса.
Программа запускает командный интерпретатор /bin/sh, известный как Bourne shell, приказывает ему исполнить команду Is -1 и перенаправляет стандартный вывод этой команды в файл ls.log.
Техника программирования, основанная на fork/exec, несколько отличается от принятой во многих других современных системах, в том числе Win32, где при создании нового процесса мы сразу же указываем программу, которую он будет исполнять.
Но вернемся к способам загрузки программ.
13.2.3 Абсолютная загрузка — до 15 мин.
Первый, самый простой, вариант состоит в том, что мы всегда будем загружать программу с одного и того же адреса. Это возможно в следующих случаях.
Система может предоставить каждому процессу свое адресное пространство. Это возможно только на процессорах, осуществляющих трансляцию виртуального адреса в физический.
Система может исполнять в каждый момент только один процесс. Так ведет себя СР/М, так же устроено большинство загрузочных мониторов для самодельных компьютеров. Похожим образом устроена система RT-H, но о пей чуть ниже.
Загрузочный файл, используемый при таком способе загрузки, называется абсолютным загрузочным модулем.
Начальное содержимое образа процесса формируется путем простого копирования модуля в память. В системе RT-11 такие файлы имеют расширение sav от saved — сохраненный.
В системе UNIX на 32-разрядных машинах также используется абсолютная загрузка. Загружаемый файл формата a.out (современные версии Unix используют более сложный формат загружаемого модуля и более сложную схему загрузки. Она содержит:
- "магическое число" — признак того, что это именно загружаемый модуль,
а не что-то другое;
- число text_size — длину области кода программы (text);
- data_siz,e — длину области инициализированных данных программы (data);
- BSS_SIZE —длину области неинициализированных данных программы (BSS);
- стартовый адрес программы.
За заголовком следует содержимое областей TEXT и DATA. Затем может следовать отладочная информация. Она нужна символьным отладчикам, но самой программой не используется.
|
|
При загрузке система выделяет процессу TEXT_SIZE байтов виртуальной памяти, доступной для чтения/исполнения, и копирует туда содержимое сегмента text. Затем отсчитывается DATA_SIZE байтов памяти, доступной для чтения/ записи, и туда копируется содержимое сегмента data.
Очистка выделяемой памяти нужна не столько для удобства программиста, сколько по соображениям безопасности: перед вновь загружаемым процессом эту память могли занимать (а при сколько-нибудь длительной работе системы почти наверняка занимали) другие процессы, которые могли использовать эту память для хранения важных и секретных данных, например паролей или ключей шифрования.
После этого выделяется пространство под стек, в стек помещаются позиционные аргументы и среда исполнения (environment), и управление передается на стартовый адрес. Процесс начинает исполняться.
13.2.4 Разделы памяти — до 15 мин.
Одним из способов обойти невозможность загружать более одной программы при абсолютной загрузке являются разделы памяти.
Идея метода состоит в том, что мы задаем несколько допустимых стартовых адресов для абсолютной загрузки. Каждый такой адрес определяет раздел памяти. Процесс может размещаться в одном разделе, или, если это необходимо — т. е. если образ процесса слишком велик — в нескольких. Это позволяет загружать несколько процессов одновременно, сохраняя при этом преимущества абсолютной загрузки.
Если мы не знаем, в какой из разделов пользователь вынужден будет загружать нашу программу, мы должны предоставить по отдельному загрузочному модулю на каждый из допустимых разделов. Понятно, что это не очень практично, поэтому разделы были вытеснены более удобными схемами "управления памятью.