Как и в случае ELF-файла, заголовок содержит общую информацию, позволяющую определить местоположение остальных компонентов (табл. 2.5).
Таблица 2.5. Поля заголовка COFF-файла
Поле |
Описание |
f_magic |
Аппаратная платформа, для которой создан файл |
f_nscns |
Количество разделов в файле |
f_timdat |
Время и дата создания файла |
f_symptr |
Расположение таблицы символов в файле |
f_nsyms |
Количество записей в таблице символов |
f_opthdr |
Размер заголовка |
f_flags |
Флаги, указывающие на тип файла, присутствие символьной информации и т.д. |
Заголовок COFF присутствует в исполняемых файлах, промежуточных объектных файлах и библиотечных архивах. Каждый исполняемый файл кроме заголовка COFF содержит заголовок a.out, хранящий информацию, необходимую ядру системы для запуска программы [16] В SCO UNIX заголовок a.out самого ядра используется программой начальной загрузки /boot для запуска ядра и передачи ему управления при инициализации системы.
(табл. 2.6).
Таблица 2.6. Поля заголовка a.out
Поле |
Описание |
vstamp |
Номер версии заголовка |
tsize |
Размер раздела инструкций (text) |
dsize |
Размер инициализированных данных (data) |
bsize |
Размер неинициализированных данных (bss) |
entry |
Точка входа программы |
text_start |
Адрес в начала сегмента инструкций виртуальной памяти |
data_start |
Адрес в начала сегмента данных виртуальной памяти |
Все файлы формата COFF имеют один или более разделов, каждый из которых описывается своим заголовком. В заголовке хранится имя раздела (.text, .data, .bss или любое другое, установленное соответствующей директивой ассемблера), размер раздела, его расположение в файле и виртуальной адрес после запуска программы на выполнение. Заголовки разделов следуют сразу за заголовком файла.
Таблицы символов и строк являются основой системы отладки. Символом является любая переменная, имя функции или метка, определенные в программе.
Каждая запись в таблице символов хранит имя символа, его виртуальный адрес, номер раздела, в котором определен символ, тип, класс хранения (автоматический, регистровый и т.д.). Если имя символа занимает больше восьми байт, то оно хранится в таблице строк. В этом случае в поле имени символа указывается смещение имени символа в таблице строк.
С помощью символьной информации можно определить виртуальный адрес некоторого символа. Одним из очевидных применений этой возможности является использование символьной информации в программах- отладчиках. Эта возможность используется некоторыми программами, например, утилитой ps(1) , отображающей состояние процессов в системе.
Выполнение программы в операционной системе UNIX
Выполнение программы начинается с создания в памяти ее образа и связанных с процессом структур ядра операционной системы, инициализации и передаче управления инструкциям программы. Завершение программы ведет к освобождению памяти и соответствующих структур ядра. Образ программы в памяти содержит, как минимум, сегменты инструкций и данных, созданные компилятором, а также стек для хранения автоматических переменных при выполнении программы.
Функция main() является первой функцией, определенной пользователем (т. е. явно описанной в исходном тексте программы), которой будет передано управление после создания соответствующего окружения запускаемой на выполнение программы. Традиционно функция main() определяется следующим образом:
main(int argc, char *argv[], char *envp[]);
Первый аргумент ( argc
) определяет число параметров, переданных программе, включая ее имя.
Указатели на каждый из параметров передаются в массиве argv[]
, таким образом, через argv[0]
адресуется строка, содержащая имя программы, argv[1]
указывает на первый параметр и т.д.. до argv[argc-1]
.
Массив envp[]
содержит указатели на переменные окружения, передаваемые программе. Каждая переменная представляет собой строку вида имя_переменной=значение_переменной
. Мы уже познакомились с переменными окружения в главе 1, когда обсуждали командный интерпретатор. Сейчас же мы остановимся на их программной "анатомии".
Стандарт ANSI С определяет только два первых аргумента функции main() — argc
и argv
. Стандарт POSIX.1 определяет также аргумент envp
, хотя рекомендует передачу окружения программы производить через глобальную переменную environ
, как это показано на рис. 2.6:
Читать дальше