Расширение синтаксиса ассемблера
Мы уже говорили что некоторые тонкости системы команд «Эверест» спрятаны за ассемблерными макросами. Пока не готов компилятор Си, нам приходится много писать на ассемблере и приходится прилагать много усилий для реализации сложных алгоритмов. Одной из проблем является необходимость помнить за что отвечает каждый из использованных регистров. Поэтому было принято решение о введении алиасов для регистров.
Простой пример — сторонний разработчик реализовал процедуру, которая возвращает указатель на голову списка, а у нас возникла необходимость посчитать количество элементов в этом списке. Обычно мы избегаем необходимости подсчитывать количество элементов в списке, вместо этого мы заводим переменную, которую увеличиваем на единицу при добавлении нового элемента и вычитаем единицу при удалении элемента. Это гораздо проще, чем каждый раз проверять все элементы списка для подсчёта их количества. Но сторонний разработчик не подумал над этим и возвращает нам лишь указатель на первый элемент списка. Проблему решает вот этот простейший код на Си:
Выше вы видите простейший контейнер для организации односвязных списков — это указатель на следующий элемент и указатель на данные, на которые ссылается элемент списка. Структура настолько же простая, насколько и универсальная. Однако, когда таких структур много и они достаточно сложны, то программисту становится сложно помнить назначение каждого регистра и повышается вероятность ошибки.
Для решения этой проблемы мы добавили возможность именовать регистры с помощью новой директивы ASSIGN.
assign r1 alias_for_structure ; Назначение имени регистру R1
Таким образом далее в тексте программы любое упоминание сочетания alias_for_structure автоматически заменяется на регистр r1.
Теперь берём на себя обязанности компилятора и вручную генерируем ассемблерный код для вышеприведённого примера программы:
Строка с комментарием «просто тест» и есть просто тест, демонстрирующая возможности адресации. В случае генерации кода компилятором она бы не появилась в этом коде. Мы добавили её чтобы показать возможности нашего ассемблера. Заглянем в дизассемблированный дамп чтобы увидеть машинный код, сгенерированный из нашего примера:
Теперь понятно, для чего мы добавили в пример лишнюю строку с чтением поля data_ptr структуры list_item — при нулевом смещении (первое поле структуры) ассемблер использует более короткую форму инструкции, что продемонстрировано на последней картинке.
Также мы обнаружили и исправили несколько небольших ошибок в ассемблере.
Наконец, мы обновили версию макроассемблера на нашем сайте, поместив в один архив версию для Windows и версию для Linux — обе версии собраны из одного и того же исходного кода. Чтобы получить исполняемые версии для Linux, вам потребуется с помощью следующей инструкции распаковать вложенный архив с исполняемым кодом для Linux:
tar xf linux_bin.tar
Оставить комментарий