[EXT]
Все для программиста!
  Статьи   Форум   Исходники   Каталог   Хостинг  
 Справочник функций

Ваш аккаунт

Логин:
Пароль:

Забыли пароль?
Регистрация

Почтовая рассылка



Подписчиков: 12748 Последний выпуск: 04.10.2006

Расширенный ассемблер: NASM

Следующая глава | Предыдущая глава | Содержание | Указатель


Глава 5: Директивы ассемблера

Перевод: AsmOS group, © 2001
Хотя NASM и пытается избежать бюрократизм ассемблеров наподобие MASM и TASM, он вынужден поддерживать несколько директив. Все они описаны в этой главе.

Существует два типа директив NASM: пользовательские и примитивные. Обычно каждая директива имеет как пользовательскую, так и примитивную форму. В большинстве случаев рекомендуется использовать пользовательскую форму директив, которая реализована как макрос, вызывающий примитивные формы. Примитивные директивы заключаются в квадратные скобки; для пользовательских директив этого не требуется.

В дополнение к описанным в этой главе универсальным директивам каждый объектный формат может опционально предоставлять дополнительные директивы, служащие для управления особенностями этого формата. Такие дополнительные директивы описываются далее в главе, посвященной выходным форматам файлов (глава 6).

5.1 BITS: Указание разрядности выполняемого кода

Директива BITS указывает, код какой разрядности должен генерировать NASM: для процессора, работающего в 16-битном режиме, или для процессора в 32-битном режиме. Соответствующим синтаксисом будет BITS 16 или BITS 32.

В большинстве случаев вам не потребуется использовать BITS явно. Объектные форматы aout, coff, elf и win32, разработанные для 32-битных операционных систем, вынуждают NASM выбирать 32-битный режим по умолчанию. Объектный формат obj позволяет вам описывать каждый сегмент как USE16 или USE32, поэтому NASM будет соответственно настраивать режим работы и здесь использование директивы BITS также не требуется.

Наиболее вероятным использование директивы BITS представляется при написании 32-битного плоского бинарного файла. (Выходной формат bin по умолчанию предназначен для 16-битного режима, т.к. он наиболее часто используется для написания DOS .COM программ, DOS .SYS драйверов устройств, а также загрузчиков).

Не нужно задавать BITS 32 для использования 32-битных инструкций в 16-битных DOS-программах; если вы это сделаете, ассемблер сгенерирует некорректный код, так как он получится 32-битным и на 16-битных платформах будет не работоспособен.

Когда NASM находится в состоянии BITS 16, инструкции, использующие 32-битные данные, префиксируются байтом 0х66, а 32-битные адреса – байтом 0х67. В состоянии BITS 32 справедливо обратное: 32-битные инструкции не нуждаются в префиксе, инструкции, использующие 16-битные данные, префиксируются байтом 0х66, а 16-битные адреса – байтом 0х67.

Директива BITS имеет абсолютно эквивалентные примитивные формы: [BITS 16] и [BITS 32]. Пользовательская форма инструкции является макросом, который не делает ничего, кроме как вызывает соответствующую примитивную форму.

5.2 SECTION или SEGMENT: Описание и изменение секций

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

Объектные форматы Unix и bin поддерживают стандартизованные имена секций: .text — для кода, .data — для данных и .bss — для неинициализированных данных. Формат obj наоборот, не признает эти имена секций специальными и более того, удаляет ведущую точку в имени любой секции.

5.2.1 Макрос __SECT__

Директива SECTION необычна тем, что ее пользовательская форма функционально отличается от примитивной. Примитивная форма [SECTION xyz] просто переключает текущую секцию на указанную. Пользовательская форма SECTION xyz сначала определяет однострочный макрос __SECT__ для примитивной директивы [SECTION], которую собирается выдать, и затем выдает ее. Таким образом, пользовательская директива

          SECTION .text

развернется в две строки:

%define __SECT__ [SECTION .text] 
          [SECTION .text]

Пользователи могут использовать это в своих собственных макросах. Например, макрос writefile, описанный в параграфе 4.2.3, может быть с успехом переписан в следующей, более изощренной форме:

%macro writefile 2+ 
          [section .data] 
%%str:    db %2 
%%endstr: 
          __SECT__ 
          mov dx,%%str 
          mov cx,%%endstr-%%str 
          mov bx,%1 
          mov ah,0x40 
          int 0x21 
%endmacro

Данная форма макроса, записывающего строку в файл, сначала временно переключается на секцию данных, используя при этом примитивную форму директивы SECTION, не модифицирующую __SECT__. Далее в секции данных объявляется строка и затем вызывается __SECT__, переключающий контекст на любую секцию, в которой пользователь работал до этого. Это исключает необходимость использования инструкции JMP (как в предыдущей версии макроса) для "перескакивания" данных, а также предотвращает возникновение ошибок в модуле OBJ формата, где пользователь потенциально может использовать различные секции кода.

5.3 ABSOLUTE: Определение абсолютных меток

О директиве ABSOLUTE можно думать как об альтернативной форме SECTION: она направляет последующий код не в физическую секцию, а в гипотетическую, начинающуюся с указанного абсолютного адреса. В данном режиме вы можете использовать только инструкции семейства RESB.

ABSOLUTE используется следующим образом:

          absolute 0x1A 
kbuf_chr  resw 1 
kbuf_free resw 1 
kbuf      resw 16

В данном примере область данных PC BIOS описана как сегмент, начинающийся с адреса 0х1А: приведенный выше код определяет kbuf_chr по адресу 0x1A, kbuf_free по адресу 0x1C и kbuf по адресу 0x1E.

Пользовательская форма ABSOLUTE, так же, как и SECTION, переопределяет макрос __SECT__ в месте своего вызова. Директивы STRUC и ENDSTRUC определены как макросы, использующие директиву ABSOLUTE (и соответственно, __SECT__).

ABSOLUTE в качестве аргумента принимает не только абсолютные константы: это может быть выражение (на самом деле критическое выражение: см. параграф 3.7), а также какое-то значение в сегменте. Например, TSR может реутилизировать свой настроечный код в качестве run-time BSS следующим образом:

          org 100h               ; это .COM - программа 
          jmp setup              ; код setup идет последним 
          ; здесь расположена резидентная часть TSR 
setup:    ; теперь идет код, инсталлирующий TSR 
          absolute setup 
runtimevar1 resw 1 
runtimevar2 resd 20 
tsr_end:

Здесь определяется несколько переменных "на верхушке" setup-кода, так что после завершения его работы это пространство может быть реутилизировано как хранилище данных для работающей TSR. Символ 'tsr_end' может быть использован для расчета общего размера резидентной части TSR.

5.4 EXTERN: Импорт символов из других модулей

Директива EXTERN подобна директиве MASM EXTRN и ключевому слову extern в С: она используется для объявления символа, который определен в некотором другом модуле. Не все объектные форматы поддерживают внешние переменные: формат bin этого не может.

Директива EXTERN принимает столько аргументов, сколько вам необходимо. Каждый аргумент является именем символа:

          extern _printf 
          extern _sscanf,_fscanf

Некоторые объектные форматы обеспечивают дополнительные возможности директивы EXTERN. В любом случае, дополнительный синтаксис отделяется от имени символа двоеточием. Например, формат obj при помощи следующей директивы позволяет вам объявить, что базой сегмента внешних символов по умолчанию должна быть группа dgroup:

          extern _variable:wrt dgroup

Примитивная форма EXTERN отличается от пользовательской тем, что одновременно может принять только один аргумент: поддержка списка аргументов реализуется на уровне препроцессора.

Вы можете объявить одну и ту же переменную как EXTERN более одного раза: NASM спокойно проигнорирует второе и последующие переопределения.

5.5 GLOBAL: Экспорт символов в другие модули

Директива GLOBAL — это обратная сторона EXTERN: если один модуль объявляет символ как EXTERN и ссылается на него, то для предотвращения ошибок компоновщика необходимо, чтобы некоторый другой модуль определил этот символ и объявил его как GLOBAL. Некоторые ассемблеры для этой цели используют директиву PUBLIC.

Директива GLOBAL, применяемая к символу, должна появляться перед определением этого символа. Она использует тот же самый синтаксис, что и EXTERN, за исключением того, что ссылается на символ, определяемый в этом же модуле. Например:

          global _main 
_main:    ; некоторый код

GLOBAL, как и EXTERN, позволяет вводить после двоеточия специфичный синтаксис объектных форматов. К примеру объектный формат elf позволяет вам указать, чем являются глобальные символы: функциями или данными:

          global hashlookup:function, hashtable:data

Как и в случае EXTERN, примитивная форма GLOBAL отличается от пользовательской восприятием одновременно только одного аргумента.

5.6 COMMON: Определение общих данных

Директива COMMON используется для объявления общих переменных. Общая переменная — это глобальная переменная, объявленная в секции неинициализированных данных, поэтому

          common intvar 4

работает так же, как и

          global intvar 
          section .bss 
intvar    resd 1

Отличие состоит в том, что если одна и та же переменная определена в разных модулях, во время связывания (сборки) эти переменные будут объединены и ссылки на intvar во всех модулях будут указывать на одно и то же место в памяти.

Директива COMMON, так же как GLOBAL и EXTERN, поддерживает специфичный синтаксис объектных форматов. Например, формат obj позволяет общим переменным быть близкими (near) или дальними (far), а формат elf — задать их выравнивание:

          common commvar 4:near  ; работает в OBJ 
          common intarray 100:4  ; работает в ELF: выравнивание про 4-байтной границе

И наконец, примитивная форма COMMON, как и в случае EXTERN и GLOBAL, отличается от пользовательской тем, что одновременно принимает только один аргумент.


Следующая глава | Предыдущая глава | Содержание | Указатель

Оставить комментарий

Оставлять комментарии могут только зарегистрированные пользователи.

Если вы не являетесь зарегистрированным пользователем, то вам необходимо зарегистрироваться. Регистрация бесплатна. Если вы уже зарегистрированы на CodeNet, то вам необходимо ввести логин и пароль в верхней (Alt-U) части страницы.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог