Этот документ описывает язык, принятый как 80386 ассемблер, который является частью Amsterdam Compiler Kit. Синтаксис описан лишь частично. В качестве примеров, показано несколько инструкций для 386.
Синтаксис чисел такой же как и в языке C. Константы 32, 040 и 0x20 представляют то же самое число, но написаны в десятичном, восьмеричном и hex формате. Правила для символьных констант и строковых последовательностей - теже самые, что и в языке C. Например, 'a' - символьная константа. Типичная строковая последовательность - "string". Выражения могут быть сформированы с операторами C, но в них должны использоваться [ and ], в случае если применяются круглые скобки. (Обычные круглые скобки требуются синтаксисом операнда).
Символы
Символы содержат буквы и цифры, а так же три специальных символа: точка, тильда и подчеркивание. Возможно также, что первый символ будет не цифрой или тильдой.
Наименования 80386 регистров сохранены и представлены ниже:
xx и exx - варианты восьми общих регистров, рассматриваемые как синонимы ассемблера. Как правило, "ax" является 16-битной частью 32-битного "eax" регистра. Ассемблер определяет, предназначение 16 или 32 битовых операциий, ища при этом инструкции или дополнение к инструкциям. Это неплохой вариант, в таком случае, можно использовать надлежащие регистры при написании сборок (трансляций) и при этом не запутать тех, кто прочитает такой код. Последняя группа, состоящая из 6 регистров сегмента, используется в качестве селектора и для режима смещения при адресации, в которой действующий адрес в данном смещении, является одним из 6 сегментов.
Названия инструкций и псевдоопераций не сохранены. Алфавитные символы в кодах операций и псевдооперациях должны быть в нижнем регистре.
Разделители
Запятые, пробелы и символы табуляции - разделители, которые могут использоваться свободно между символами, но не в пределах символов. Между операндами допустимы только лишь запятые.
Комментарии
Символ комментария '!'. Строка за таким символом игнорируется и является комментарием.
Коды операции
Коды операции упомянуты ниже. Примечания: (1) Различные наименования для той же самой инструкции отделены '/'. (2) Квадратные скобки ([]) указывают, что 0 или 1 в вложенных символах могут быть включены. (3) Фигурные скобки ({}) работают точно так же за исключением того, что один из вложенных символов должен быть включен. Таким образом квадратные скобки указывают выбор, тогда как фигурные скобки указывают на то, что выбор должен быть сделан.
Передача данных mov[b] dest, source ! Процедура копирует указанное число байт из аргумента источника (Source) в аргумент приема (Dest); pop dest ! Pop стэк push source ! Push стэк xchg[b] op1, op2 ! Обмен слово/байт xlat ! Перевод o16 ! Операции над объектами в 16 бит вместо 32 бит
Вход/Выход in[b] source ! Вход от исходного порта ввода/вывода in[b] ! Вход из DX порта ввода/вывода out[b] dest ! Вывод в Dest порт ввода/вывода out[b] ! вывод в DX порт ввода/вывода
Адрес объекта lds reg,source ! Загрузка reg и DS из источника les reg,source ! Загрузка reg и ES из источника lea reg,source ! Адрес эффективности загрузки и источника reg и DS {cdsefg}seg ! Определяющий seg регистр для последующих инструкций a16 ! Использует 16 битовый способ адресации вместо 32 битов
Флаг передачи lahf ! Загрузка AH из регитсра флага popf ! Pop флаги pushf ! Push флаги sahf ! Сохранение AH в флаге регистра
Сложение aaa ! Суммирование результата BCD сложения add[b] dest,source ! Сложение adc[b] dest,source ! Сложение с переносом daa ! Десятичная коррекция при сложении inc[b] dest ! Инкримент 1
Вычитание aas ! Коррекция ASCII-формата для вычитания sub[b] dest,source ! Вычитание sbb[b] dest,source ! Вычитание с заёмом das ! Десятичная коррекция при вычитании dec[b] dest ! Декремент neg[b] dest ! Получение дополнительного кода cmp[b] dest,source ! Сравнение
Умножение aam ! Коррекция ASCII-формата для умножения imul[b] source ! Умножение с учетом знака mul[b] source ! Умножение без учета знака
Деление aad ! Коррекция ASCII-формата для деления o16 cbw ! Преобразует знаковый бит регистра AL в регистр AH. o16 cwd ! Преобразование слова в двойное слово (AX в DX) cwde ! Знаковое деление AX на EAX cdq ! Знаковое деление EAX into EDX idiv[b] source ! Выполняет деление знакового делимого div[b] source ! Выполняет деление беззнакового делимогоUnsigned divide
Операции со строками cmps[b] ! Сравнение строки (байты или слова) lods[b] ! Загрузка строки (из байтов или слов) movs[b] ! Пересылка строки байт или строки слов rep ! Повтор следующей инструкции до ECX=0 repe/repz ! Повтор следующей инструкции до ECX=0 и ZF=1 repne/repnz ! Повтор следующей инструкции до ECX!=0 и ZF=0 scas[b] ! Просмотр строки (из байтов или слов) stos[b] ! Запись в строку (из байтов или слов)
Контроль передачи As принимается как количество специальных скачков (переходов) в коде операции, которая может быть собрана к инструкции или со смещением байта и может достигнуть значений только в пределах от -126 до +129 байт или инструкции с 32-битовым смещением. Ассемблер автоматически выбирает байт или инструкцию смещения слова.
Инструкции 'call', 'jmp' и 'ret' могут быть внутрисегментными или межсегментными. Межсегментные версии отображаются с суффиксом 'f'.
Безусловные jmp[f] dest ! Безусловный переход (8 или 32 бит) call[f] dest ! Вызов процедуры ret[f] ! Возврат из подпрограммы
Условные ja/jnbe ! Переход, если более. Переход, если флаг CF=0 и ZF=0. jae/jnb/jnc ! Переход, если более или равно. Переход, если флаг CF=0. jb/jnae/jc ! Переход, если ниже. Переход, если флаг CF=1. jbe/jna ! Переход, если ниже или равно. Переход, если флаг CF=1 и ZF=1. jg/jnle ! Переход, если более. Переход, если флаг SF=0F и ZF=0. jge/jnl ! Переход, если больше или равно. Переход, если флаг SF=0F. jl/jnqe ! Переход, если ниже. Переход, если флаг SF<>0F. jle/jgl ! Переход, если ниже либо равно. Переход, если флаг SF<>0F или ZF=1. je/jz ! Переход, если равно. Переход, если флаг ZF=0. jne/jnz ! Переход, если не равно. Переход, если флаг ZF=0. jno ! Переход, если нет переполнения. Переход, если флаг OF=0. jo ! Переход, если переполнение. Переход, если флаг OF=1. jnp/jpo ! Безусловный переход jp/jpe ! Переход, если есть паритет. Переход, если флаг PF=1. jns ! Переход, если нет знака. Переход, если флаг SF=0. js ! Переход, если знак. Переход, если флаг SF=1.
Итеративный контроль jcxz dest ! Переход если ECX = 0 loop dest ! Декремент ECX и переход если CX != 0 loope/loopz dest ! Декремент ECX и переход если ECX = 0 и ZF = 1 loopne/loopnz dest ! Декремент ECX и переход если ECX != 0 и ZF = 0
Прерывания int n ! Программное прерывание n into ! Прерывание по переполнению iretd ! Возврат после обработки прерывания
Флаги операций clc ! Сброс флага переноса cld ! Сброс флага направления cli ! Сброс флага разрешения прерываний cmc ! Перключение флага переноса stc ! Установка флага переноса в 1 std ! Установка флага направления sti ! Установка флага разрешения прерываний
Счетчик адресов
Специальный символ '.' - счетчик адреса, значением которого является адрес первого байта инструкции, в которой символ имеется и может использоваться в выражениях.
Сегменты
Существует четыре различных сегмента ассемблирования: text, rom, data и bss. Сегменты объявлены и отобраны sect псевдооперацией. Это общепринятое правило для объявления все сегментов в заголовке файла и сборки такой, как например, эта:
.sect .text; .sect .rom; .sect .data; .sect .bss
Ассемблер принимает до 16 различных сегментов, но MINIX допускает использование только четырех. В принципе что-либо может быть собрано в любой сегмент, но MINIX bss сегмент может содержать только некалиброванные данные. Следует отметить, что символ '.' обращается к местоположению в текущем сегменте.
Метки
Могут быть двух типов: имя и число. Метки состоят из названия, сопровождаемого двоеточием (:).
Числовые метки - содержат только цифры. Самый близкий 0: на меткке может ссылаться как 0f (направление вперед) или 0b (назад).
Стандартный синтаксис
Каждая строка состоит из единственного утверждения. Разрешены пробелы, а также комментарий строк.
Допустимые инструкции
Наиболее общая форма инструкции - метка:
opcode operand1, operand2 ! comment
Семантические выражения
Следующие операторы могут использоваться: + - * / & | ^ ~ << (сдвиг влево) >> (сдвиг вправо) - (унарный минус). Используется 32-битовая арифметика целого числа.
Режимы адресации
Ниже приведен список поддерживаемых способов адресации, каждый сопровождается примером.
constant mov eax, 123456 direct access mov eax, (counter) register mov eax, esi indirect mov eax, (esi) base + disp. mov eax, 6(ebp) scaled index mov eax, (4*esi) base + index mov eax, (ebp)(2*esi) base + index + disp. mov eax, 10(edi)(1*esi)
Любая из констант или символов может быть заменена в выражениях. Разрешен прямой доступ, константы и смещения могут быть любым типом в выражении. Индекс увеличения с масштабом 1 может быть записан без '1 *'.
Вызов и переход
Инструкции вызов 'call' и переход 'jmp' могут быть can be interpreted as a load into the instruction pointer.
Символам можно присвоить значения одним из двух способов. Символ может использоваться как метка '.' для текущего сегмента с изменяемым типом. Также, символу можно присвоить имя записав следующую форму:
symbol = expression символ = выражение
в которой символу присваивают значение и тип его аргументов.
Распределение памяти
Место может быть зарезервировано для байтов, слов и последовательностей, использующих псевдооперации. Его могут составлять один или более операндов, для каждого из которых, сгенерируется значение, размер которого - байт, 2-байтовое слово или слово длинной 4 байта. Например:
.data1 2, 6 ! выделение 2 байтов определенных к 2
and 6 .data2 3, 0x10 ! выделение 2 слов определенных к 3 and 16 .data4 010 ! выделение целого числа определенного к 8 .space 40 ! выделение 40 байтов из нулей
Выделение 50 (десятичных) байтов хранения, определяя первые два байта к 2 и 6, следующие два слова к 3 и 16, а затем одно целое число со значением 8 (010 октальное), последние 40 байтов - нули.
Строковые последовательности
Псевдооперации .ascii and .asciz берут один аргумент последовательности и генерируют ASCII коды для записей в последовательности. Последний операнд автоматически заканчивает последовательность с пустым указателем (0) байт. Например,
.ascii "hello" .asciz "world\n"
Выравнивание
Иногда бывает необходимо сделать так, чтобы последующий пункт начиналсяся в слове, предложении или даже 16-байтовом адресе. .align ноль или больше пустого байта в том случае, если текущее местоположение - кратное число аргумента .align.
Контроль за сегментом
Каждый собранный пункт входит в один из четырех сегментов: text, rom, data или bss. Используются .sect псевдооперанды с аргументми последующих пунктов, входящих в специфический сегмент.
Внешние Имена
Символу можно присвоить глобальные возможности включающие его в .define псевдооперации. Множественные наименования могут быть перечислены через запятую. Это должно использоваться для того, чтобы экспортировать символы, определенные в текущей программе. Наименования, не определенные в текущей программе обработаны как "неопределенные внешние" автоматически, хотя это общепринято, чтобы выполнить это явным образом с .extern псевдооперацией.
Common
.comm псевдооперация объявляет память, в которой это может быть распростронено более чем в одном модуле. Есть два параметра: название и абсолютное выражение, дающее размер в байтах области и названное символом. Тип символа становится внешним. Оператор может появиться в любом сегменте. Если Вы думаете, что это имеет некоторое отношение к языку FORTRAN, Вы правы.
Примеры
В каталоге ядра, есть несколько искодных кодов файлов, которые стоит рассматривать как примеры. Однако, следует заметить, что эти файлы созданы для управления через препроцессор Си. (Самый первый символ - #, символизирует об этом). Таким образом они содержат многочисленные конструкции, которые не являются чистый ассемблером. Для настощих примеров ассемблера, соберите любую Cи программу представленную в MINIX с использованием флага S. В результате создастся файл ассемблера с суффиксом и именем, что и Си файл, но оканчивающийся .s суффиксом.