Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
flor_apparato-orientirovnnoe_prog.doc
Скачиваний:
96
Добавлен:
15.06.2014
Размер:
926.72 Кб
Скачать

1.4. Описание сегментной структуры программы

Действительная структура программы в машинных кодах включает так называемые сегменты памяти. Эта структура невидима из языков высокого уровня, но является неизбежной и даже благодарной реальностью машинных структур данных. Основное назначение таких сегментов в современных архитектурах - обеспечить защитой от ошибочного доступа машинные коды команд и области данных. (В область команд запрещается что-либо записывать в процессе выполнения программы, а из области данных управляющему устройству процессора запрещается читать коды, автоматически интерпретируя их как коды машинных команд.) Получается, что, как минимум, машинная программа должна иметь два сегмента: сегмент машинных кодов (кодов команд) и сегмент данных. Заметим, что только в однозадачной ОС MS-DOS, где не было или не использовались указанные выше средства защиты сегментов друг от друга, можно было все машинные коды программы - и данные, и коды команд - размещать в одном единственном сегменте, причем все сегменты в этой ОС могли иметь максимальный размер всего в 64 Кбайта.

Для описания сегментов служит специальное наименование директивы, обозначаемое словом SEGMENT, причем в этом случае можно записывать служебное слово как строчными, так и прописными буквами. (Синонимом этого служебного слова является слово SECTION, которое можно всегда использовать для обозначения сегмента.) В простейшем случае директива сегмента имеет единственный аргумент, который задает имя описываемого сегмента. С учетом ориентации ряда ОС на язык Си, как язык соглашений взаимодействия с системой, рекомендуемые названия сегментов кодов команд и данных есть, соответственно, .text и .data, причем начальная точка обозначения формальным образом входит в состав имени.

Другой неожиданной для начинающей особенностью ассемблерных программ является необходимость явного обозначения машинной инструкции, с которой должна начать выполняться программа. Это отвечает естественно заложенной в архитектуру компьютеров возможности начать выполнение любой программы с любого места в области памяти, занятой кодами машинных команд. Любая отметка места в памяти, относящаяся как к машинным командам, так и к данным, представляет собой на языке ассемблера так называемую метку. Метка на языке ассемблера есть просто имя, соотносимое началу строки ассемблерной программ и размещаемое в начале этой строки. Традиционная методика использования меток требует, чтобы обозначение метки в том месте, где она именует строку программы, завершалась служебным символом двоеточия. В ассемблере nasm это требование является необязательным, но мы будем им пользоваться для отметок в тексте собственно машинных команд. В ассемблерах типа Intel требуются метки, обозначающие места в тексте машинных команд, обязательно завершать двоеточием, а метки, обозначающие данные, как правило, используются без завершающих двоеточий.

Место, с которого начинает выполняться программа, называется точкой входа. Метка точки входа в программу на языке NASM должна обязательно быть объявлена видимой извне объектного модуля, который возникает из исходного текста при традиционной методике создания программы. Такое объявление осуществляет директива GLOBAL. Назначение и возможности этой директивы гораздо шире, чем указание с ее помощью точки входа, но более подробное обсуждение данного вопроса будет проведено позднее. Использование директивы GLOBAL заключается в записи после ключевого слова этой директивы того имени, которое предполагается задать как глобальное. (В общем случае в одной этой директиве может быть через запятые указано много имен, которые предполагается использовать как глобальные.)

Программа - компоновщик в Linux - по сложившейся традиции требует имени _start в качестве обозначения начала программы (так как точка входа программы всегда одна, то такой выбор не несет никакого мыслимого ограничения). Указанное имя начинается со служебного символа подчеркивания, которое считается также входящим в состав этого имени. В общем случае имена в NASM могут состоять из алфавитно-цифровых символов, начинающихся с буквы, причем символ подчеркивания считается буквой. Кроме того, служебные имена могут начинаться с одной или двух точек. Использование служебных имен будет описываться особо по ходу изложения.

В ассемблерах типа Intel было принято высокоумное, но несколько громоздкое в применении решение обозначать специальными служебными словами не только начала сегмента программы, но и конец сегмента программы. Для обозначения конца сегмента программ здесь предназначена директива со служебным именем ENDS, причем в этой директиве обязательно должно быть записано и имя того сегмента, который она завершает. Такое решение призвано сократить число ошибок при написании программы, но, в связи с крайне скромным числом сегментов в современных программах, теперь такое решение кажется скорее красивым, чем целесообразным. В указанных ассемблерах типа Intel именование как директивы SEGMENT, так и директивы ENDS производится записью имени перед служебным словом директивы. (Следует, правда, отметить, что так называемый Turbo ассемблер фирмы Borland/Inprise имеет режим, в котором имя сегмента следует за служебным словом, а не наоборот.) Кроме рассмотренной особенности описания сегментов, ассемблеры типа Intel используют специальную директиву END для указания завершения, по назначению и форме очень напоминающую одноименную директиву в языке Pascal. В указанных же ассемблерах директива END используется также для указания метки точки входа.

Таким образом, сегментная структура программы для NASM имеет вид

GLOBAL _start

SEGMENT .text

_start:

. . . ; задание машинных команд на данном ассемблере

SEGMENT .data

. . . ; описание данных на ассемблере NASM

причем сегменты .text и .data могут быть переставлены местами. Аналогичная же программа на ассемблере MASM или TASM будет иметь общий вид

имя_сегмента_кода SEGMENT

имя_точки_входа:

. . . ; задание машинных команд на данном ассемблере и служебных конструкций

имя_сегмента_кода ENDS

имя_сегмента_данных SEGMENT

. . . ; описание данных на ассемблере MASM или TASM

имя_сегмента_данных ENDS

END имя_точки_входа

где также сегменты данных и команд могут быть переставлены местами. Забегая вперед, отметим, что в современных ОС Windows (32-битных полноценных ОС, в отличие от уже почти забытой промежуточной 16-битной Windows и MS-DOS) имена сегментов кода и данных должны задаваться по некоторым фиксированным соглашениям, так что практически тоже могут считаться постоянными.

В современных ОС исходные описания сегментов используют не один сегмент данных, а по крайней мере две его модификации. Сегмент с традиционным наименованием .data или DATA применяется для инициализируемых данных. Характерной особенностью этих данных является задание начального значения для каждой единицы исходного описания данных. Для размещения данных, исходное описание которых не содержит задания начального значения, принято наименование .bss или BSS. Следует учитывать, что транслятор NASM по-разному «относится» к содержимому указанных модификаций сегментов данных. Если программист делает попытку помещения неинициализированных им данных в сегмент с именем .data или DATA, то выдается предупреждение, а область самих таких данных заполняется нулевыми байтами. В свою очередь, попытка объявить данные (т.е. описать области размещения данных без задания их значений) в сегментах .bss или BSS приводит к сообщаемой ошибке.

Соседние файлы в предмете Системное программное обеспечение