Директивы в ассемблере что это
Расширенный ассемблер: NASM
Глава 5: Директивы ассемблера
Хотя NASM и пытается избежать бюрократизм ассемблеров наподобие MASM и TASM, он вынужден поддерживать несколько директив. Все они описаны в этой главе.
Существует два типа директив NASM: пользовательские и примитивные. Обычно каждая директива имеет как пользовательскую, так и примитивную форму. В большинстве случаев рекомендуется использовать пользовательскую форму директив, которая реализована как макрос, вызывающий примитивные формы. Примитивные директивы заключаются в квадратные скобки; для пользовательских директив этого не требуется.
В дополнение к описанным в этой главе универсальным директивам каждый объектный формат может опционально предоставлять дополнительные директивы, служащие для управления особенностями этого формата. Такие дополнительные директивы описываются далее в главе, посвященной выходным форматам файлов (глава 6).
5.1 BITS : Указание разрядности выполняемого кода
Не нужно задавать BITS 32 для использования 32-битных инструкций в 16-битных DOS-программах; если вы это сделаете, ассемблер сгенерирует некорректный код, так как он получится 32-битным и на 16-битных платформах будет не работоспособен.
5.2 SECTION или SEGMENT : Описание и изменение секций
Директива SECTION ( SEGMENT это абсолютно эквивалентный синоним) указывает, в какую секцию выходного файла будет ассемблирован код, который вы пишете. В некоторых объектных форматах количество и имена секций фиксированы; в других пользователь может сделать их столько, сколько захочет. Поэтому если вы захотите переключиться на секцию, которая в данный момент не существует, директива SECTION может либо вызвать сообщение об ошибке, либо создать новую секцию.
5.2.1 Макрос __SECT__
развернется в две строки:
5.3 ABSOLUTE : Определение абсолютных меток
ABSOLUTE используется следующим образом:
ABSOLUTE в качестве аргумента принимает не только абсолютные константы: это может быть выражение (на самом деле критическое выражение: см. параграф 3.7), а также какое-то значение в сегменте. Например, TSR может реутилизировать свой настроечный код в качестве run-time BSS следующим образом:
Здесь определяется несколько переменных «на верхушке» setup-кода, так что после завершения его работы это пространство может быть реутилизировано как хранилище данных для работающей TSR. Символ ‘ tsr_end ‘ может быть использован для расчета общего размера резидентной части TSR.
5.4 EXTERN : Импорт символов из других модулей
Директива EXTERN подобна директиве MASM EXTRN и ключевому слову extern в С: она используется для объявления символа, который определен в некотором другом модуле. Не все объектные форматы поддерживают внешние переменные: формат bin этого не может.
Директива EXTERN принимает столько аргументов, сколько вам необходимо. Каждый аргумент является именем символа:
Примитивная форма EXTERN отличается от пользовательской тем, что одновременно может принять только один аргумент: поддержка списка аргументов реализуется на уровне препроцессора.
Вы можете объявить одну и ту же переменную как EXTERN более одного раза: NASM спокойно проигнорирует второе и последующие переопределения.
5.5 GLOBAL : Экспорт символов в другие модули
5.6 COMMON : Определение общих данных
Директива COMMON используется для объявления общих переменных. Общая переменная это глобальная переменная, объявленная в секции неинициализированных данных, поэтому
работает так же, как и
Отличие состоит в том, что если одна и та же переменная определена в разных модулях, во время связывания (сборки) эти переменные будут объединены и ссылки на intvar во всех модулях будут указывать на одно и то же место в памяти.
Директивы Ассемблера
Группа директив для указания типа процессора
Директивы указания типа процессора задают набор используемых инструкций.
Директивы для указания сегментов
Директива SEGMENT
Определяет сегмент с заданным именем name. Если сегмент с таким именем уже был определен ранее, то данный сегмент интерпретируется как продолжение предыдущего.
BYTE | выравнивание не выполняется. Сегмент может начинаться с любого адреса памяти |
WORD | выравнивание на границу слова (2 байта) |
DWORD | выравнивание на границу двойного слова (4 байта) |
PARA | выравнивание по границе параграфа (16 байт). Используется по-умолчанию. |
PAGE | выравнивание на границу в 256 байт |
USE16 | сегмент с 16-разрядной адресацией. Максимальный размер сегмента 64 Кб |
USE32 | сегмент с 32-разрядной адресацией. Максимальный размер сегмента 4 Гб. В модели памяти FLAT используется по-умолчанию |
Директива ENDS
Определяет конец сегмента.
Директива ASSUME
Задает сегментный регистр, который будет использоваться для вычисления действующего адреса для всех меток и переменных, определенных для сегмента или группы сегментов с указанным именем.
Директивы для упрощенного указания сегментов
Директива .MODEL
Задает модель памяти для упрощенных директив определения сегментов.
C | Аргументы передаются через стек, справа налево. Стек очищает вызывающая программа. |
PASCAL, BASIC | Аргументы передаются через стек, слева направо. Стек очищает вызываемая подпрограмма. |
STDCALL | Аргументы передаются через стек, справа налево. Стек очищает вызываемая подпрограмма. |
Директива .CODE или CODESEG
Определяет начало сегмента кода. Если задали среднюю или большую модель памяти, то за директивой может следовать необязательное имя, которое указывает имя сегмента. По-умолчанию имя сегмента _TEXT.
Директива .DATA или DATASEG
Определяет начало инициализированного сегмента данных.
Директива .DATA?
Определяет в модуле начало неинициализированного сегмента данных.
Директива .CONST
Определяет начало сегмента данных-констант.
Сегменты .DATA, .DATA?, .CONST помещаются в одну группу с именем DGROUP
Директива .STACK или STACK
Определяет начало сегмента стека, выделяя количество байт, заданное параметром. Если размер не указывается, выделяется 1024 байт.
Группа директив для резервирования памяти
Резервирует область памяти, заданного директивой размера, с указанным именем, и инициализирует значением выражения. Выражение может быть числом, строкой символов, специальным символом «?«, а также выражением с использованием директивы DUP.
Повторяет операцию выделения памяти для указанных данных столько раз, сколько задано значением счетчика
Директива STRUC (STRUCT)
Определяет структуру данных с заданным именем, содержащую поля. В каждом поле для определения его размера используются обычные директивы выделения данных (DB, DW и т.д.). Поля структуры могут быть именованными или нет.
Директива ENDS
Определяет конец структуры.
Директива UNION
Группа директив модификации размера указателей
Используются когда возникает неоднозначность в размере операнда команды. Например когда в ячейку памяти записывается число, то компилятор не может определить число какого размера требуется записать, и в этом случае требуется укзать директиву модификации размера.
Директивы определения процедур
Директива PROC
Определяет начало процедуры с указанным именем.
Директива ENDP
Определяет окончание процедуры
Директива USES
Показывает, какие регистры или элементы данных, состоящие из одной лексемы, вы хотите занести в стек в начале охватывающей процедуры. Перед возвратом управления из процедуры эти регистры будут извлекаться из стека. Вы должны использовать эту директиву перед первой инструкцией, которая генерирует в процедуре реальный код.
Директива LOCAL
В процедуре директива LOCAL определяет имена, которые доступны в стеке через отрицательные смещения относительно регистра BP. Если указан идентификатор, то ему присваивается количество байт, выделенных на локальные переменные (размер всего блока локальных переменных в байтах).
Директивы для макроопределений
Директива MACRO
Определяет начало макроопределения с указанным именем. У макроопредения могут быть заданы необязательные параметры, которые будут использоваться при подстановке тела макроопределения в текст программы.
Директива ENDM
Определяет окончание макроопределения
Директива REPT
Повторяет блок операторов, заданный между директивами REPT и ENDM столько раз, сколько задается выражением. Блок операторов должен заканчиваться директивой ENDM.
Директива IRP
Повторяет блок операторов, заданный между директивой IRP и ENDM со строковой подстановкой. Аргументами может быть любой текст: символы, строки, числа и т.д. Для каждого указанного аргумента ассемблирование блока операторов выполняется только один раз. При каждом ассемблировании блока для каждого вхождения «параметра» в операторах подставляется следующий аргумент в списке.
Другие директивы
Директива COMMENT
Позволяет задать многострочный комментарий, ограниченный с начала и с конца заданным символом-ограничителем.
Директива EQU
Определяет имя как строку, псевдоним или число, содержащие результат вычисления выражения.
Директива END
Отмечает конец исполняемого модуля и задает начальный адрес, с которого будет исполняться программа.
Директива EVEN
Округляет счетчик адреса до следующего четного адреса
Директива SEG
Возвращается адрес сегмента выражения со ссылкой на память
Директива OFFSET
Возвращает смещение выражения в текущем сегменте (или в группе, которой принадлежит сегмент, если используются упрощенные директивы определения сегментов).
Директива ORG
Устанавливает счетчик инструкций в текущем сегменте в соответствии с адресом, задаваемым выражением.
Директива RADIX
Задает основание системы счисления для целочисленных констант (2, 8, 10 или 16)
Директива SIZE
Возвращает размер элемента данных, выделенного для переменной
Директивы в ассемблере что это
Компилятор поддерживает ряд директив. Директивы не транслируются непосредственно в код. Вместо этого они используются для указания положения в программной памяти, определения макросов, инициализации памяти и т.д. Список директив приведён в таблице 3.5
Таблица 3.5 Список директив ассемблера
Директива | Описание |
BYTE | Зарезервировать байты в ОЗУ |
CSEG | Программный сегмент |
DB | Определить байты во флэш или EEPROM |
DEF | Назначить регистру символическое имя |
DEVICE | Определить устройство для которого компилируется программа |
DSEG | Сегмент данных |
DW | Определить слова во флэш или EEPROM |
ENDM | Конец макроса |
EQU | Установить постоянное выражение |
ESEG | Сегмент EEPROM |
EXIT | Выйти из файла |
INCLUDE | Вложить другой файл |
LIST | Включить генерацию листинга |
LISTMAC | Включить разворачивание макросов в листинге |
MACRO | Начало макроса |
NOLIST | Выключить генерацию листинга |
ORG | Установить положение в сегменте |
SET | Установить переменный символический эквивалент выражения |
Все директивы предваряются точкой.
Директива BYTE резервирует байты в ОЗУ. Если Вы хотите иметь возможность ссылаться на выделенную область памяти, то директива BYTE должна быть предварена меткой. Директива принимает один обязательный параметр, который указывает количество выделяемых байт. Эта директива может использоваться только в сегменте данных(смотреть директивы CSEG и DSEG). Выделенные байты не инициализируются.
Директива CSEG определяет начало программного сегмента. Исходный файл может состоять из нескольких программных сегментов, которые объединяются в один программный сегмент при компиляции. Программный сегмент является сегментом по умолчанию. Программные сегменты имеют свои собственные счётчики положения, которые считают не побайтно, а пословно. Директива ORG может быть использована для размещения кода и констант в необходимом месте сегмента. Директива CSEG не имеет параметров.
Директива DB резервирует необходимое количество байт в памяти программ или в EEPROM. Если Вы хотите иметь возможность ссылаться на выделенную область памяти, то директива DB должна быть предварена меткой. Директива DB должна иметь хотя бы один параметр. Данная директива может быть размещена только в сегменте программ (CSEG) или в сегменте EEPROM (ESEG).
Директива DEF позволяет ссылаться на регистр через некоторое символическое имя. Назначенное имя может использоваться во всей нижеследующей части программы для обращений к данному регистру. Регистр может иметь несколько различных имен. Символическое имя может быть переназначено позднее в программе.
.DEF Символическое_имя = Регистр
Директива DEVICE позволяет указать для какого устройства компилируется программа. При использовании данной директивы компилятор выдаст предупреждение, если будет найдена инструкция, которую не поддерживает данный микроконтроллер. Также будет выдано предупреждение, если программный сегмент, либо сегмент EEPROM превысят размер допускаемый устройством. Если же директива не используется то все инструкции считаются допустимыми, и отсутствуют ограничения на размер сегментов.
.DEVICE AT90S1200 |AT90S2313 | AT90S2323 | AT90S2333 | AT90S2343 | AT90S4414 | AT90S4433 | AT90S4434 | AT90S8515 | AT90S8534 | AT90S8535 | ATtiny11 | ATtiny12 | ATtiny22 | ATmega603 | ATmega103
Директива DSEG определяет начало сегмента данных. Исходный файл может состоять из нескольких сегментов данных, которые объединяются в один сегмент при компиляции. Сегмент данных обычно состоит только из директив BYTE и меток. Сегменты данных имеют свои собственные побайтные счётчики положения. Директива ORG может быть использована для размещения переменных в необходимом месте ОЗУ. Директива не имеет параметров.
Директива определяет конец макроопределения, и не принимает никаких параметров. Для информации по определению макросов смотрите директиву MACRO.
Директива EQU присваивает метке значение. Эта метка может позднее использоваться в выражениях. Метка которой присвоено значение данной директивой не может быть переназначена и её значение не может быть изменено.
.EQU метка = выражение
Директива ESEG определяет начало сегмента EEPROM. Исходный файл может состоять из нескольких сегментов EEPROM, которые объединяются в один сегмент при компиляции. Сегмент EEPROM обычно состоит только из директив DB, DW и меток. Сегменты EEPROM имеют свои собственные побайтные счётчики положения. Директива ORG может быть использована для размещения переменных в необходимом месте EEPROM. Директива не имеет параметров.
Встретив директиву EXIT компилятор прекращает компиляцию данного файла. Если директива использована во вложенном файле (см. директиву INCLUDE), то компиляция продолжается со строки следующей после директивы INCLUDE. Если же файл не является вложенным, то компиляция прекращается.
Встретив директиву INCLUDE компилятор открывает указанный в ней файл, компилирует его пока файл не закончится или не встретится директива EXIT, после этого продолжает компиляцию начального файла со строки следующей за директивой INCLUDE. Вложенный файл может также содержать директивы INCLUDE.
Директива LIST указывает компилятору на необходимость создания листинга. Листинг представляет из себя комбинацию ассемблерного кода, адресов и кодов операций. По умолчанию генерация листинга включена, однако данная директива используется совместно с директивой NOLIST для получения листингов отдельных частей исходных файлов.
После директивы LISTMAC компилятор будет показывать в листинге содержимое макроса. По умолчанию в листинге показывается только вызов макроса и передаваемые параметры.
С директивы MACRO начинается определение макроса. В качестве параметра директиве передаётся имя макроса. При встрече имени макроса позднее в тексте программы, компилятор заменяет это имя на тело макроса. Макрос может иметь до 10 параметров, к которым в его теле обращаются через @0-@9. При вызове параметры перечисляются через запятые. Определение макроса заканчивается директивой ENDMACRO.
По умолчанию в листинг включается только вызов макроса, для разворачивания макроса необходимо использовать директиву LISTMAC. Макрос в листинге показывается знаком +.
Директива NOLIST указывает компилятору на необходимость прекращения генерации листинга. Листинг представляет из себя комбинацию ассемблерного кода, адресов и кодов операций. По умолчанию генерация листинга включена, однако может быть отключена данной директивой. Кроме того данная директива может быть использована совместно с директивой LIST для получения листингов отдельных частей исходных файлов
Директива SET присваивает имени некоторое значение. Это имя позднее может быть использовано в выражениях. Причем в отличии от директивы EQU значение имени может быть изменено другой директивой SET.
.SET имя = выражение
Выражения
Компилятор позволяет использовать в программе выражения которые могут состоять операндов, операторов и функций. Все выражения являются 32-битными.
Операнды
Могут быть использованы следующие операнды:
Ссылка ассемблера OS X
Ассемблерные директивы
В этой главе описываются ассемблерные директивы (также известный как псевдо операции или псевдооперация в секунду), которые позволяют управление действиями ассемблера.
Директивы для обозначения текущего раздела
Связанный с каждым разделом в каждом сегменте неявный счетчик адреса, начинающийся в нуле и постепенно увеличивающийся 1 для каждого байта, собранного в раздел. Нет никакого способа явно сослаться на определенный счетчик адреса, но директивы, описанные здесь, могут использоваться для «активирования» счетчика адреса для раздела, делая его текущим счетчиком адреса. В результате ассемблер начинает собираться в раздел, связанный с тем счетчиком адреса.
.section
.zerofill
Типы раздела и атрибуты
Довольный раздел имеет тип, сообщающий редактору связей о специальной обработке, необходимой для элементов в том разделе. Наиболее распространенная форма специальной обработки для разделов, содержащих литералы (строки, константы, и т.д.), где только одна копия литерала необходима в выходном файле, и тот же литерал может использоваться всеми ссылками во входных файлах.
Атрибуты раздела записывают дополнительную информацию о разделе, который редактор связей может использовать в обработке того раздела. Например, pure_instructions атрибут указывает, что раздел содержит только допустимые машинные команды.
Идентификаторы типов
Следующие разделы описывают идентификаторы типов раздела.
регулярный (S_REGULAR)
cstring_literals (S_CSTRING_LITERALS)
A cstring_literals раздел содержит завершенные нулем литеральные символьные строки языка C. Редактор связей помещает только одну копию каждого литерала в раздел выходного файла и перемещает ссылки на различные копии того же литерала к одной копии в выходном файле. Не может быть никаких записей перемещения для раздела этого типа, и все ссылки на литералы в этом разделе должны быть в диапазоне адресов для определенного ссылаемого литерала. Последний байт в разделе этого типа должен быть нулевым байтом, и строки не могут содержать нулевые байты в своих организациях. Пример a cstring_literals раздел один для литеральных строк, появляющихся в организации функции ANSI C, где компилятор принимает решение сделать такие строки только для чтения.
4byte_literals (S_4BYTE_LITERALS)
8byte_literals (S_8BYTE_LITERALS)
literal_pointers (S_LITERAL_POINTERS)
symbol_stubs (S_SYMBOL_STUBS)
A symbol_stubs раздел содержит тупики символа, которые являются последовательностями машинных команд (весь одинаковый размер) используемый для того, чтобы лениво связать неопределенные вызовы функции во время выполнения. Если вызов к неопределенной функции выполняется, выходы компилятора вызов к тупику символа вместо этого, и тегирует тупик с косвенным символом, указывающим, для какого символа тупик. На передаче в тупик символа программа выполняет инструкции, в конечном счете достигающие кода для косвенного символа, связанного с тем тупиком. Вот выборка ассемблерного кода на основе функции func() содержа только вызов к неопределенной функции foo() :
На IA-32 команда перехода указывает динамическому компоновщику. В первый раз, когда тупик вызывают, динамический компоновщик изменяет инструкцию так, чтобы это перешло к реальной функции в последующих вызовах.
Статический редактор связей помещает только одну копию каждого тупика в раздел выходного файла для определенного косвенного символа и перемещает все ссылки на тупики с тем же косвенным символом к тупику в выходном файле. Далее, статический редактор связей устраняет тупик, если он решает, что цель находится в том же модуле связи и не нуждается в перенаправлении во время выполнения. Никакие глобальные символы не могут быть определены в symbol_stubs разделы.
На PPC тупик может относиться только к себе, один ленивый указатель символа (именующий тот же косвенный символ как тупик), и dyld_stub_binding_helper() функция.
lazy_symbol_pointers (S_LAZY_SYMBOL_POINTERS)
non_lazy_symbol_pointers (S_NON_LAZY_SYMBOL_POINTERS)
A non_lazy_symbol_pointers раздел содержит 4-байтовые указатели символа, содержащие значение косвенного символа, связанного с указателем, который может быть установлен в любое время, прежде чем любой код делает ссылку на него. Эти указатели используются кодом для ссылки на неопределенные символы. Первоначально эти указатели не имеют никакого интересного значения, но перезаписываются редактором динамического канала со значением символа для связанного косвенного символа, прежде чем любой код сможет сделать ссылку на него.
Вот пример ассемблерного кода, ссылающегося на элемент в неопределенной структуре. Соответствующий код C был бы:
Ассемблерный код PowerPC мог бы быть похожим на это:
mod_init_funcs (S_MOD_INIT_FUNC_POINTERS)
mod_term_funcs (S_MOD_TERM_FUNC_POINTERS)
объединенный (S_COALESCED)
Идентификаторы атрибута
Следующие разделы описывают идентификаторы атрибута.
ни один (0)
S_ATTR_SOME_INSTRUCTIONS
no_dead_strip (S_ATTR_NO_DEAD_STRIP)
no_dead_strip атрибут раздела указывает, что определенный раздел не должен быть мертво разделен. См. Директивы для Невыполняемого кода, Разделяющего для получения дополнительной информации.
no_toc (S_ATTR_NO_TOC)
live_support (S_ATTR_LIVE_SUPPORT)
live_support атрибут раздела указывает, что блоки раздела не должны быть мертво разделены, если они код ссылки, который жив, но ссылка, необнаруживаемые. См. Директивы для Невыполняемого кода, Разделяющего для получения дополнительной информации.
pure_instructions (S_ATTR_PURE_INSTRUCTIONS)
strip_static_syms (S_ATTR_STRIP_STATIC_SYMS)
strip_static_syms разделите средние значения атрибута, что статические символы в этом разделе могут быть разделены от соединенных изображений, использующихся с динамическим компоновщиком, когда также разделяется отладочная информация. Это обычно используется с a coalesced раздел, имеющий частный extern символы, так, чтобы после соединения и частного экстерна символы были превращены в статические символы, они могут быть разделены для оставления свободного места в соединенном изображении.
self_modifying_code (S_ATTR_SELF_MODIFYING_CODE)
self_modifying_code атрибут раздела идентифицирует раздел с кодом, который может быть изменен динамическим компоновщиком. Например, тупики символа IA-32 реализованы как команды перехода, первоначально указывающие динамическому компоновщику, но изменяющиеся динамическим компоновщиком для указания на реальный символ.