Связывание программ на разных языках.
Поскольку уже давно на языке ассемблера часто кодируют только фрагменты программ, их необходимо связывать с остальными частями программной системы, написанными на других языках программирования. Это достигается двумя основными способами:
· На этапе компиляции — вставка в исходный код программы на языке высокого уровня ассемблерных фрагментов (англ. inlineassembler) с помощью специальных директив языка. Способ удобен для несложных преобразований данных, но полноценного ассемблерного кода с данными и подпрограммами, включая подпрограммы со множеством входов и выходов, не поддерживаемых языком высокого уровня, с его помощью сделать невозможно.
· На этапе компоновки при раздельной компиляции. Для взаимодействия компонуемых модулей достаточно, чтобы импортируемые функции (определённые в одних модулях и используемые в других) поддерживали определённое соглашение о вызове (англ. callingconventions). Написаны же отдельные модули могут быть на любых языках, в том числе и на языке ассемблера [7].
Синтаксис языка ассемблера определяется системой команд конкретного процессора.
Типичный формат записи команд:
[метка:] [ [префикс] мнемокод [операнд {, операнд}]] [;комментарий]
где мнемокод — непосредственно мнемоника инструкции процессору. К ней могут быть добавлены префиксы (повторения, изменения типа адресации и пр.).
В качестве операндов могут выступать константы, адреса регистров, адреса в оперативной памяти и пр. Различия между синтаксисом Intel и AT&T касаются в основном порядка перечисления операндов и указания различных методов адресации [1].
Используемые мнемоники обычно одинаковы для всех процессоров одной архитектуры или семейства архитектур (среди широко известных — мнемоники процессоров и контроллеров x86, ARM, SPARC, PowerPC, M68k). Они описываются в спецификации процессоров. Возможные исключения:
· если ассемблер использует кроссплатформенный AT&T-синтаксис (оригинальные мнемоники приводятся к синтаксису AT&T);
· если изначально существовало два стандарта записи мнемоник (система команд была наследована от процессора другого производителя).
Наиболее известными ассемблерами для операционной системы DOSявлялись TASM, MASMиWASM. Также в своё время был популярен Ассемблер А86.
При появлении операционной системы Windowsпоявилось расширении TASM, позволившее создавать программы для выполнения в среде Windows.
Так же существует открытый проект ассемблера, версии которого доступны под различные операционные системы, и который позволяет получать объектные файлы для этих систем. Называется этот Ассемблер NASM [2].
Макроассемблер- макропроцессор базовым языком которого является язык ассемблера.
Процесс трансляции программы на языке ассемблер в объектный код принято называть- ассемблированием. В отличии от компилирования, ассемблирование- более или менее однозначный и обратимый процесс.
Дизассемблер- транслятор, преобразующий машинный код, объектные файлы или библиотечные модули в текст программы на языке ассемблер.
Примеры программ-дизассемблеров:
Ida, Beye, CADt, Hiew, Sourcer, HTeditor, Radare.
По режиму дизассемблеры делятся на:
-автоматические
-интерактивные
Примером автоматических дизассемблеров может служить Sourcer. Такие дизассемблеры генерируют готовый листинг, который можно затем править в текстовом документе[5].
Примером интерактивного- IDA. Он позволяет изменять правила дизассемблирования и является весьма удобным инструментом для исследования программ.
Дизассемблеры могут быть однопроходные и многопроходные. Основная трудность при работе дизассемблера- отличить данные от машинного кода, поэтому на первых проходах автоматически или интерактивно собирается информация о границах процедур и функций, а на последнем проходе формируется итоговый листинг. Интерактивность позволяет улучшить это процесс, так как просматривая дамп дизассемблированной области памяти программист сразу может выделить строковые константы, дать содержательные имена известным точкам входа, прокомментировать разобранные им фрагменты программы.
Ассемблерная инструкция, состоит из мнемоники команды и списка аргументов через запятую (один, два или три в зависимости от инструкции).
В языке ассемблера имеются средства записи целых и вещественных чисел, а также символьных строк и отдельных символов. Целые числа могут быть со знаком и без знака, а также записанные в двоично-десятичном формате. Для целых чисел и символов в составе команд микропроцессора и, соответственно, в языке ассемблера, есть средства обработки- анализа, сравнения, поиска и проч. Для вещественных чисел таких средств в самом микропроцессоре нет, они содержаться в арифметическом сопроцессоре.
Рассмотрим сначала целые числа без знака и со знаком. Числа без знака получили своё название потому, что среди этих чисел нет отрицательных. Это самый вид чисел: они представляют собой весь диапазон двоичных чисел, которые можно записать в байте, слове или двойном слове. Для байта числа без знака могут принимать значения от 00h(0) доFFh(255); для слова-от 0000h(0) доFFFFh (65535); для двойного слова- от 00000000h(0) доFFFFFFFF(4294967295) [6].
Предложения.
Программа на ассемблере состоит из предложений, каждое из которых записывается на отдельной строке, <предложение>… Переносить предложение на следующую строку или записывать два предложения на одной строке нельзя.
Директивы определения данных.
Для того чтобы в программе на ASM зарезервировать ячейки памяти под переменные и константы, необходимо воспользоваться директивами определения данных- с названиями db- (описывает данные размером в байт),
dw-(размером в слово), dd- (размером в двойное слово).
В простейшем случае в директивеdb,dwилиdd описывается одна константа, которой дается имя для последующих ссылок на неё. По этой директиве ассемблер формирует машинное представление константы и записывает в очередную ячейку памяти. Адрес этой ячейки становиться значением имени: все вхождения имени в программу ассемблер будет заменять на этот адрес.
Имена, указанные в директивах db, dwиdd, называются именами переменных (в отличии от меток- имени команд).
В ASM числа записываются в нормальном виде в системах счисления с основанием 10, 16, 8 или 2.
Десятичные числа записываются как обычно, за шестнадцатиричным числом ставится буква (если число начинается с “цифры” А, В, …, F, то вначале обязателен 0), за восьмиричным числом- буква qили о, за двоичным числом- буква b.
Константы-символы описываются в директиве двояка: указывается либо код символа (целое от 0 до 255), либо сам символ в кавычках (одинарных или двойных); в последнем случае ассемблер сам заменит символ на его код.