Многоэтапная обработка пользовательской программы

Чтобы лучше представлять себе все детали адресации и размещения программы в памяти, рассмотрим общую схему многоэтапной обработки пользовательской программы, используемую в любой ОС. Схема представлена на рис. 15.1.


Рис. 15.1. Многоэтапная обработка пользовательской программы.

Исходный кодпрограммы (в форме текстового файла) на языке высокого уровня или на ассемблере преобразуется компилятором или ассемблером в объектный модуль, содержащий бинарные выполняемые машинные команды и таблицу символов, определенных и использованных в данном модуле кода. Рассмотренная фаза называется временем компиляции.

Однако объектный модуль не может непосредственно исполняться, так как он содержит неразрешенные ссылки на внешние модули и их компоненты. Следующая фаза обработки программы – редактирование связей. Редактор связей (linker)– системная программа, которая получает на вход один или несколько объектных модулей, а на выходе выдает загрузочный модуль– двоичный код, образованный кодом нескольких объектных модулей, в котором разрешены все межмодульные ссылки - для каждого символа, внешнего для данного объектного модуля A, найден соответствующий символ (процедуры, переменной и т.д.) из другого модуля B, на который ссылается модуль A, и код соответственно откорректирован, т.е. он правильно адресует внешний символ.

Загрузочный модуль может быть загружен в память для исполнения с помощью еще одной системной программы – загрузчика (loader),который получает на вход загрузочный модуль и файлы с бинарными кодами системных библиотек,которые использует программа. Загрузчик, объединяя код программы с кодами системных библиотек, создает бинарный образ программы в памяти.

Фаза вызова редактора связей и загрузчика носит общее название время загрузки. Во многих ОС функции редактора связей и загрузчика, с целью экономии времени обработки программы в системе, объединены в одной системной программе – редакторе связей и загрузчике (linker and loader).Например, в системе UNIX редактор связей и загрузчик называется ld (Linker and loaDer).Объединенному загрузчику и редактору связей на вход передается список объектных модулей и список библиотек, и в результате он генерирует исполняемый код. Фаза редактирования связей и загрузки часто на программистском слэнге называется линковкой (linking).Будем далее использовать именно этот короткий и выразительный термин.

Вот пример последовательности фаз обработки программы в терминах команд системы UNIX:

 

сс –c program.c // Компиляция исходного кода на Си.

// В рабочей директории – объектный модуль program.o

ld program.o mylibrary.a // редактирование связей и загрузка

// В рабочей директории – исполняемый код с именем по умолчанию a.out

a.out // Исполнение программы

// В стандартный вывод (по умолчанию – на консоль)

// выдаются результаты программы

В примере предполагается, что в файле program.cхранится исходный код программы на Си, которая использует библиотечные функции из библиотеки mylibrary.a. Отметим соглашения в системе UNIX о расширениях имен файлов: .c –исходный код на Си, .o– объектный модуль, .a– бинарный файл статически линкуемой библиотеки(аббревиатура от термина archive). Исполняемый код (executable) в UNIX не имеет стандартного расширения имени, но имеет полное имя по умолчанию – несколько архаичное имя a.out(аббревиатура от asembler output).

В Windows соглашения о расширениях имен файлов несколько иные: .obj– объектный модуль, .exe– исполняемый код, .lib– статически линкуемая библиотека.

Отличить объектный модуль от загрузочного очень просто: они сильно отличаются по своему размеру. Объясняется это тем, что в загрузочном модуле присутствует полностью или частично код статически линкуемых библиотек, а также гораздо больше, чем у объектного модуля, таблица символов – она содержит все символы библиотек и других объектных модулей, слинкованных в единую исполняемую программу.

На этапе выполнения, при первом обращении к ним из программы, в память загружаются динамически линкуемые библиотеки (dymanically linked libraries).Данная разновидность библиотек, реализованная во всех современных ОС, позволяет сэкономить память, занимаемую образом исполняемого кода, который при статической линковке с библиотеками оказывается очень велик. Подробнее об этом – позже в данной лекции.