Fasm (язык программирования)
Из Википедии, бесплатной энциклопедии
![]() | В статье не хватает ссылок на источники (см. рекомендации по поиску). |
fasm | |
---|---|
Класс языка | язык ассемблера |
Тип исполнения | компилируемый |
Появился в | 1999 |
Автор | Томаш Грыштар |
Расширение файлов | .asm - для файлов кода, .inc - для подключаемых файлов |
Система типов | отсутствует |
Основные реализации | ассемблер fasm, ассемблер fasmarm, [[Fresh_(IDE)]] |
Испытал влияние | изначально TASM, NASM, в новейшем периоде fasmg (язык программирования) |
Повлиял на | fasmg (язык программирования) |
Лицензия | Вариант лицензии BSD с возможно анти-GPL исключением |
Сайт | flatassembler.net |
fasm (сокращение от flat assembler) — 32-битная разновидность языка ассемблера.
История
[править | править код]Проект был начат в 1999 году Томашом Грыштаром (пол. Tomasz Grysztar).
Принципы
[править | править код]Fasm стремится использовать минимально возможный набор директив препроцессора, т.е. в предустановленном наборе директив не допускается внедрение новых директив, функциональность которых может быть достигнута имеющимся набором директив.
Синтаксис
[править | править код]Символьный интервал языка
[править | править код]Ориентированность на широкий спектр операционных систем (не все из которых поддерживают многобайтовые символы), ограничивает используемую в исходных текстах палитру допустимых символов до однобайтовых вариаций.
Под абстракцией «символ» воспринимается символ с привязкой к конкретному ASCII коду, а не конкретному начертанию.
В палитре символов можно выделить отдельные группы:
- местозаполнитель между токенами:
- ASCII код 9 (Табуляция)
- ASCII код 32 (Пробел)
- разделитель строк:
- ASCII код 10 (Разрыв строки)
- ASCII код 13 (Возврат каретки)
- кавычки:
- ASCII код 34 (Двойные кавычки «"»)
- ASCII код 39 (Одинарные кавычки «'»)
- специальные символы:
- ASCII код 35 (Решетка «#»)
- ASCII код 38 (Амперсанд «&»)
- ASCII код 40 (Открывающая круглая скобка «(»)
- ASCII код 41 (Закрывающая круглая скобка «)»)
- ASCII код 42 (Знак умножения «*»)
- ASCII код 43 (Знак плюс «+»)
- ASCII код 44 (Запятая «,»)
- ASCII код 45 (Знак минус «-»)
- ASCII код 46 (Точка «.»)
- ASCII код 47 (Знак деления «/»)
- ASCII код 58 (Двоеточие «:»)
- ASCII код 59 (Точка с запятой «;»)
- ASCII код 60 (Знак меньше «<»)
- ASCII код 61 (Знак равно «=»)
- ASCII код 62 (Знак больше «>»)
- ASCII код 91 (Открывающая квадратная скобка «[»)
- ASCII код 92 (Обратный слеш «\»)
- ASCII код 93 (Закрывающая квадратная скобка «]»)
- ASCII код 96 (Апостроф «`»)
- ASCII код 123 (Открывающая фигурная скобка «{»)
- ASCII код 124 (Вертикальная черта «|»)
- ASCII код 125 (Закрывающая фигурная скобка «}»)
- ASCII код 126 (Тильда «~»)
- Запрещенный для использования в исходном тексте:
- ASCII код 0 (Пустой символ)
- ASCII код 26 (Подстановка «→»)
- Заглавные латинские буквы:
- ASCII код 65 (Буква «A») по ASCII код 90 (Буква «Z»)
- Строчные латинские буквы:
- ASCII код 97 (Буква «a») по ASCII код 122 (Буква «z»)
- Все остальные символы
Текст исходного файла
[править | править код]Исходные файлы чаще всего представляют собой текстовые файлы, у таких файлов текст представлен всем их содержимым. Но никто не ограничивает в качестве исходных использовать любые двоичные файлы, содержащие внутри себя не только текст, но и запрещенные для текстовых файлов символы. У таких файлов текст будет отсечен до первого встреченного запрещенного для использования в исходном тексте символа.
Каждая строка текста исходных файлов может быть пустой или содержать полезную нагрузку и/или текст комментария.
Текст комментария
[править | править код]Единственный предустановленный тип комментария – однострочный, каждый такой комментарий начинается с символа точки с запятой «;» и заканчивается разрывом строки.
Сцепление строк
[править | править код]Полезная нагрузка может быть визуально распределена на несколько строк. Если в строке исходного файла последним символом, не включенным в комментарий (не считая следующих после него символов табуляции и пробелов), будет символ обратного слеша «\», то часть или всю полезную нагрузку этой строки можно перенести на следующую строку.
Исходный текст
[править | править код]Исходный текст представляет собой последовательность строк основного исходного файла с вкраплением в местах подключения дополнительных исходных файлов строк этих файлов, с вкраплением в них строк уже подключенных к ним файлов, и так с неограниченным уровнем вложенности. Уровень вложенности хоть и неограничен, но должен быть конечным (т.е. не бесконечно замкнутым сам в себя).
Исходный текст по количеству строк и полезной нагрузке идентичен тексту исходных файлов, его отличает лишь отсутствие комментариев и тому, что полезная нагрузка, ранее распределенная на несколько строк символом обратного слеша «\», объединена в одну строку, а последующие строки-доноры этого распределения сделаны пустыми.
Подобно тому как любой обычный текст состоит из слов и знаков препинания, исходный текст также состоит из элементов, которые можно категоризировать.
Токены
[править | править код]Полезная нагрузка исходного текста представлена в виде последовательности элементов (токенов), каждый из которых может принадлежать одному из трех разных типов: 1 - самостоятельный символ, 2 - непрерывный многосимвольный токен и 3 - строка в кавычках.
Первый тип токена – представляет собой односимвольный элемент и воспринимается в тексте инструкции как самостоятельный символ независимо от того отделен ли он от текста соседних элементов или выполнен с ними слитно. Палитра односимвольных элементов немногочисленна: «+-*/=<>()[]{}:,|&~#`» - является подмножеством специальных символов.
Второй тип токена – представляет собой многосимвольный элемент, последовательность символов которого в тексте инструкции начинается с символа отличного от кавычек (двойных «"» и одинарных «'»), выполнена слитно и не включает самостоятельных символов.
Третий тип токена – также представляет собой многосимвольный элемент, но последовательность символов которого в тексте инструкции начинается с символа кавычек (не важно двойных «"» и одинарных «'») и не заканчивается пока в пределах строки не будет встречен символ такой же кавычки, даже символ точки с запятой «;» будучи встреченным в пределах такой последовательности не открывает никакого комментария, а просто становится символом этой последовательности. Если после завершающей кавычки слитно стоит символ такой же кавычки, то в последовательность включается 1 символ этой кавычки, а сама последовательность продолжается до следующего такого же символа кавычек. Внешние открывающая и закрывающая кавычки не становятся частью элемента, они лишь выполняют роль индикатора для его типизации.
Примечание: поскольку каждый токен целиком находится на одной строке и является частью исходного текста, внутри токена не могут встретится символы, обозначающие конец строки или текста: не могут быть частью токена символы ASCII код 0 (Пустой символ), ASCII код 26 (Подстановка «→»), ASCII код 10 (Разрыв строки), ASCII код 13 (Возврат каретки).
Литералы
[править | править код]Непрерывные многосимвольные токены или литералы дополнительно делятся на две группы: 1 - символьные литералы и 2 - числовые литералы. Отличие между этими двумя группами многосимвольных элементов только в первом символе: числовые литералы начинаются с цифры или символа «$», в то время как символьные литералы обязательно начинаются с любого другого символа допустимого внутри непрерывного токена. Таким образом, числа, записанные, не важно, десятичными цифрами, шестнадцатеричными или двоичными, предваренными ли префиксом «$» или «0x» или завершенными суффиксами «b», «d», «h» все они являются подмножеством числовых литералов.
Предустановленные ключевые слова
[править | править код]Предустановленные токены:
- Препроцессинговые директивы: define, include, irp, irps, irpv, macro, match, postpone, purge, rept, restore, restruc, struc.
- Внутримакросовые директивы: common, forward, local, reverse.
- Спецсимволы этапа препроцессинга: file, line.
Предустановленные литералы (и самостоятельные символы):
- Бинарные операторы: +, -, *, /, and, mod, or, shl, shr, xor.
- Унарные операторы: +, -, bsf, bsr, not, plt, rva.
- Операторы директив: align, as, at, defined, definite, dup, eq, eqtype, from, in, on, ptr, relativeto, used.
- Размеры операндов: byte, word, dword, fword, pword, qword, tbyte, tword, xword, yword, zword, dqword, qqword, dqqword.
- Директивы определения данных: db, dd, df, dp, dq, dt, du, dw, rb, rd, rf, rp, rq, rt, rw, file.
Двойственность синтаксиса
[править | править код]Компиляция исходного текста происходит в несколько стадий, возьмем только две из них: предварительная обработка исходного текста и непосредственно сборка инструкций в бинарный вид.
На стадии ассемблер (сборки инструкций в бинарный вид) становятся известными адресные пространства, размеры, занимаемые различными структурами и инструкциями, типизируются литералы, т.е. появляется возможность проверять типы литералов, но повлиять на обработку текста на этой стадии уже нельзя. С другой стороны, на стадии препроцессинга (предварительной обработки исходного текста) все вышеперечисленное использовать в вычислениях нельзя, зато можно провести подсчет количества каких-нибудь параметров, сравнить какой-нибудь фрагмент текста с образцом, произвести какие-то манипуляции с самим исходным текстом на основе этих вычислений или сравнений.
Переменные
[править | править код]Каждая из вышеописанных стадий требует собственных переменных, т.к. различны и требования к их значениям и требования к именам этих переменных.
Строковые переменные
[править | править код]Поскольку на стадии препроцессинга происходит предворительная обработка текста, а исходный код на этой стадии представляет собой текст, хоть и токенизированный, но текст, то и переменные для этой стадии в качестве значения принимают целые строки текста произвольной длины, собственно, поэтому эти переменные называются строковыми. Более того строковые переменные хранят в себе не только текущее значение, но и всю историю присваивания значений. С исходным текстом можно провести преобразования, как на основе текущего значения таких переменных, так и на основе всей истории присвоенных ранее значений, на основе наличия в истории определенного значения или на основе самого факта инициализации такой переменной каким-то значением. В отношении таких переменных всегда присутствует возможность откатить присвоение последнего значения и делать этот откат вплоть до состояния, когда она еще не была инициализирована никаким значением.
В качестве имени такой переменной можно использовать абсолютно любой непрерывный многосимвольный токен не являющийся предустановленным символом в качестве предпроцессинговой директивы или любой ее вариации в верхнем и нижнем регистрах.
Числовые литералы (или в том числе предопределенные представления чисел)
[править | править код]На стадии ассемблера(сборки) исходный код уже представляет собой последовательности типизированных литералов. Числовым литералам отведена роль хранить в себе подмножество представлений допустимых чисел, т.е. быть предопределенными числовыми константами. Статус предопределенной и не переопределяемой константы распространен на все числовые литералы, просто те из них, что не являются представлениями допустимых чисел, являются константами ошибки или, так сказать, не допустимы к использованию в вычислениях.
Внутри самих числовых литералов есть также разделение на типы, притом критерием такого разделения является не факт бытия представлением числа, а факт бытия представлением числа с плавающей точкой. Т.е. числовые литералы представлены в двух типах числа с плавающей точкой и условно целые числа (включающих в себя числа и нечисла-ошибки).
Числовые переменные
[править | править код]На стадии ассемблера(сборки) возникает море всего, что можно посчитать, вычислить. Ориентированность на написание кода в том числе для 64-разрядных адресных пространств диктует под эти вычисления отводить минимум 64 разряда, а для естественности операций сравнения (т.е. чтобы не было разночтений в трактовке значения старшего 64го разряда –число слишком большое или наоборот число отрицательное), под отрицательность числа вводится дополнительный 65й разряд, оставляя однозначный смысл для 64го разряда – старший значащий бит числа.
Все эти вычисления не обошлись бы без переменных, способных хранить такие значения, поскольку хранить нужно числа, то и переменные называются числовые. Более того, числовые переменные хранят не просто 65 битов числа, но еще и признак того, перемещаем ли адрес. В отличие от строковых переменных, если числовой переменной значение присваивается единожды в исходном тексте, то она получает статус числовой константы и становится доступна инициализированной этой константой везде в исходном тексте. В отношении числовых переменных недоступна история значений, доступно каждый раз только текущее значение, но проверить в отношении нее можно как факт ее инициализации в принципе, так и факт того, что ее инициализация предшествовала любому месту в исходном тексте. Более того проверить можно и факт того, использована ли переменная где-то в исходном тексте. Также можно проверить у переменной признак перемещаемого адреса.
Любые предустановленные литералы нельзя использовать в качестве имени числовой переменной, поэтому в качестве имени числовой переменной можно использовать только символьные литералы, да и то из их множества необходимо вынуть все предустановленные литералы во всех вариациях верхнего и нижнего регистра. Также не имеет практической ценности использование в качестве имени числовой переменной имен препроцессорных директив, хоть и использовать переменные с такими именами можно, но их будет невозможно инициализировать, синтаксис присвоения значения такой переменной вступит в конфликт с запуском самой препроцессорной директивы.
Метки
[править | править код]Метка – особый тип числовых переменных или, даже правильнее сказать, числовых констант.
К имени метки предъявляются те же требования, что и к именам числовых переменных, но хранимое значение в метке расширено: в ней можно хранить до двух дополнительных слагаемых-регистров, один из которых может быть индексирован на 2,4,8, при отсутствии индексированного регистра, в качестве первого регистра слагаемого может быть любой основной регистр, в том числе, например, eip. А еще метки могут хранить размер данных или кода который ими отмечен.
Есть только одно место в коде, где недопустимо обозначение метки никаким из способов – это между препроцессинговой директивой и открывающей фигурной скобкой, начинающей тело этой директивы.
В остальных же случаях метку в коде можно обозначить тремя способами:
- В начале строки указать имя метки и сопроводить его двоеточием. Следующая за двоеточием часть строки пригодна для любой полезной нагрузки, в том числе для определения еще одной метки любым из трех способов, но не пригодна для использования директивы fix. Метка определенная таким образом безразмерная, а ее значение будет равным текущей позиции в адресном пространстве соответствующей позиции этой метки в коде.
- В начале строки указать литерал определения метки label затем имя метки. Если сразу после имени метки не указывать литерал размера операнда и в самом конце этой конструкции не переопределять значение метки, подобно метке определенной первым способом она будет безразмерной, а ее значение будет равным текущей позиции в адресном пространстве соответствующей позиции этой метки в коде. Если же будет указан литерал размера операнда, то у метки будет этот указанный размер. Переопределить же значение метки можно, используя литерал оператора директив at, следующее за этим литералом числовое выражение станет значением этой метки.
- В начале строки указать имя метки и сразу за ним директиву определения данных. Метка определенная таким образом будет иметь размер соответствующий размеру элемента данных, последовательность которого(ых) определена, зарезервирована или взята из файла директивой определения данных (например для директив file,db и rb размер будет равен 1 байту потому что эти директивы обрабатывают последовательности байт). Значение же метки будет равным текущей позиции в адресном пространстве соответствующей позиции этой метки в коде.
Ссылки
[править | править код]- Официальный сайт (англ.)
- Руководство пользователя (англ.)