Операционная система UNIX
Шрифт:
На следующей стадии эти файлы с помощью редактора связей ld(1) связываются друг с другом и с различными библиотеками, включая стандартную библиотеку по умолчанию и библиотеки, указанные пользователем в качестве параметров. При этом редактор связей может выполняться в двух режимах: статическом и динамическом, что задается соответствующими опциями. В статическом, наиболее традиционном режиме связываются все объектные модули и статические библиотеки (их имена имеют суффикс ".а"), производится разрешение всех внешних ссылок модулей и создается единый исполняемый файл, содержащий весь необходимый для выполнения код. Во втором случае, редактор связей по возможности подключает разделяемые библиотеки (имена этих библиотек имеют суффикс ".so"). В результате создается исполняемый файл, к которому в процессе запуска на выполнение будут подключены все разделяемые объекты. В обоих случаях по умолчанию создается исполняемый файл с именем a.out.
Для достаточно простых задач все фазы автоматически
или эквивалентной ей
которые создают исполняемый файл с именем prog. В этом случае умалчиваемое имя исполняемого файла (a.out) изменено на prog с помощью опции -о.
Впрочем, указанные стадии можно выполнять и раздельно, с использованием команд cc(1) и ld(1). Заметим, что на самом деле команда cc(1) является программной оболочкой и компилятора и редактора связей, которую и рекомендуется использовать при создании программ.
Проиллюстрируем процесс создания более сложной программы с помощью конкретных вызовов команд.
Создадим промежуточные объектные файлы file1.o и file2.o
Создадим исполняемый файл с именем prog, используя промежуточные объектные файлы и библиотеку libnsl.a или libnsl.so
Форматы исполняемых файлов
Виртуальная память процесса состоит из нескольких сегментов или областей памяти. Размер, содержимое и расположение сегментов в памяти определяется как самой программой, например, использованием библиотек, размером кода и данных, так и форматом исполняемого файла этой программы. В большинстве современных операционных систем UNIX используются два стандартных формата исполняемых файлов — COFF (Common Object File Format) и ELF (Executable and Linking Format).
Описание форматов исполняемых файлов может показаться лишним, однако представление о них необходимо для описания базовой функциональности ядра операционной системы. В частности, информация, хранящаяся в исполняемых файлах форматов COFF и ELF позволяет ответить на ряд вопросов весьма важных для работы приложения и системы в целом:
Какие части программы необходимо загрузить в память?
Как создается область для неинициализированных данных?
Какие части процесса должны быть сохранены в дисковой области свопинга (специальной области дискового пространства, предназначенной для временного хранения фрагментов адресного пространства процесса), например, при замещении страниц, а какие могут быть при необходимости считаны из файла, и таким образом не требуют сохранения?
Где в памяти располагаются инструкции и данные программы?
Какие библиотеки необходимы для выполнения программы?
Как связаны исполняемый файл на диске, образ программы в памяти и дисковая область свопинга?
На рис. 2.3 приведена базовая структура памяти для процессов, загруженных из исполняемых файлов форматов COFF и ELF, соответственно. Хотя расположение сегментов различается для этих двух форматов, основные компоненты одни и те же. Оба процесса имеют сегменты кода (text), данных (data), стека (stack). Как видно из рисунка, размер сегментов данных и стека может изменяться, а направление этого изменения определяется форматом исполняемого файла. Размер стека автоматически изменяется операционной системой, в то время как управление размером сегмента данных производится самим приложением. Эти вопросы мы подробно обсудим в разделе "Выделение памяти" далее в этой главе.
Рис. 2.3. Исполняемые образы программ форматов COFF и ELF
Сегмент данных включает инициализированные данные, копируемые в память из соответствующих разделов исполняемого файла, и неинициализированные данные, которые заполняются нулями перед началом выполнения процесса. Неинициализированные данные часто называют сегментом BSS.
Формат ELF
Формат ELF имеет файлы нескольких типов, которые до сих пор мы называли по-разному, например, исполняемый файл или объектный файл. Тем не менее стандарт ELF различает следующие типы:
1. Перемещаемый файл (relocatable file), хранящий инструкции и данные, которые могут быть связаны с другими объектными файлами. Результатом такого связывания может быть исполняемый файл или разделяемый объектный файл.
2. Разделяемый объектный файл (shared object file) также содержит инструкции и данные, но может быть использован двумя способами. В первом случае, он может быть связан с другими перемещаемыми файлами и разделяемыми объектными файлами, в результате будет создан новый объектный файл. Во втором случае, при запуске программы на выполнение операционная система может динамически связать его с исполняемым файлом программы, в результате чего будет создан исполняемый образ программы. В последнем случае
речь идет о разделяемых библиотеках.3. Исполняемый файл хранит полное описание, позволяющее системе создать образ процесса. Он содержит инструкции, данные, описание необходимых разделяемых объектных файлов, а также необходимую символьную и отладочную информацию.
На рис. 2.4 приведена структура исполняемого файла, с помощью которого операционная система может создать образ программы и запустить программу на выполнение.
Рис. 2.4. Структура исполняемого файла в формате ELF
Заголовок имеет фиксированное расположение в файле. Остальные компоненты размещаются в соответствии с информацией, хранящейся в заголовке. Таким образом заголовок содержит общее описание структуры файла, расположение отдельных компонентов и их размеры.
Поскольку заголовок ELF-файла определяет его структуру, рассмотрим его более подробно (табл. 2.4).
Таблица 2.3. Поля заголовка ELF-файла
Поле | Описание |
---|---|
е_ident[] | Массив байт, каждый из которых определяет некоторую общую характеристику файла: формат файла (ELF), номер версии, архитектуру системы (32-разрядная или 64-разрядная) и т.д. |
e_type | Тип файла, поскольку формат ELF поддерживает несколько типов |
e_machine | Архитектура аппаратной платформы, для которой создан данный файл. В табл. 2.4 приведены возможные значения этого поля |
e_version | Номер версии ELF-формата. Обычно определяется как EV_CURRENC (текущая), что означает последнюю версию |
e_entry | Виртуальный адрес, по которому системой будет передано управление после загрузки программы (точка входа) |
e_phoff | Расположение (смещение от начала файла) таблицы заголовков программы |
е_shoff | Расположение таблицы заголовков секций |
е_ehsize | Размер заголовка |
e_phentsize | Размер каждого заголовка программы |
e_phnum | Число заголовков программы |
e_shentsize | Размер каждого заголовка сегмента (секции) |
е_shnum | Число заголовков сегментов (секций) |
e_shstrndx | Расположение сегмента, содержащего таблицу строк |
Таблица 2.4. Значения поля e_machine заголовка ELF-файла
Значение | Аппаратная платформа |
---|---|
ЕМ_М32 | AT&T WE 32100 |
ЕМ_SPARC | Sun SPARC |
ЕМ_386 | Intel 80386 |
ЕМ_68K | Motorola 68000 |
EM_88K | Motorola 88000 |
ЕМ_486 | Intel 80486 |
ЕМ_860 | Intel i860 |
ЕМ_MIPS | MIPS RS3000 Big-Endian |
EM_MIPS_RS3_LE | MIPS RS3000 Little-Endian |
EM_RS6000 | RS6000 |
EM_PA_RISC | PA-RISC |
EM_nCUBE | nCUBE |
EM_VPP500 | Fujitsu VPP500 |
EM_SPARC32PLUS | Sun SPARC 32+ |