Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Флоренсов А.Н. УП Системное программное обеспечение.docx
Скачиваний:
45
Добавлен:
28.06.2021
Размер:
148.95 Кб
Скачать

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

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

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

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

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

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

В ассемблерах типа Intel было принято несколько громоздкое в применении решение обозначать специальными служебными словами не только начало, но и конец сегмента программы. Для обозначения конца сегмента программы здесь предназначена директива со служебным именем ENDS, причем в этой директиве обязательно должно быть записано и имя того сегмента, который она завершает. Такое решение призвано сократить число ошибок при написании программы, но, в связи с крайне скромным числом сегментов в современных программах, теперь такое решение кажется скорее красивым, чем целесообразным. В указанных ассемблерах типа Intel задание имени как в директиве SEGMENT, так и в директиве ENDS производится записью имени перед служебным словом директивы. Кроме рассмотренной особенности описания сегментов, ассемблеры типа 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 имена сегментов кода и данных также должны задаваться по некоторым фиксированным соглашениям, так что практически то же могут считаться постоянными.

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

Название этого специализированного сегмента программирования раскрывается как «Block Started by Symbol», которое звучит не очень информативно, поэтому профессиональные пользователи рекомендуют трактовку Better Saver Space. Этот сегмент предназначен для неинициализированных данных программы, поэтому по существу проблемы не требует хранения в кодах исполняемого файла. Практически неинициализированные данные могут быть указаны как помещаемые в сегменте с именем .datа, но тогда байты, соответствующие им, будут храниться в соответствующем месте исполняемого файла, увеличивая его объем. Практически использование секции .bss приводит только к сокращению объема исполняемого файла, что для современных программистов не является предметом внимания.