data ассемблер что это

Ассемблер. Базовый синтаксис

Обновл. 16 Сен 2021 |

Программы на ассемблере могут быть разделены на три секции:

Секции ассемблера

Секция data используется для объявления инициализированных данных или констант. Данные в этой секции НЕ могут быть изменены во время выполнения программы. Вы можете хранить константные значения и названия файлов в этой секции. Синтаксис объявления:

Секция bss используется для объявления переменных. Синтаксис объявления:

Комментарии

Комментарии в ассемблере должны начинаться с точки с запятой ( ; ). Они могут содержать любой печатный символ, включая пробел. Комментарий может находиться как на отдельной строке:

Так и на строке со стейтментом:

Стейтменты

В ассемблере есть три вида стейтментов:

Выполняемые инструкции (или просто «инструкции») — сообщают процессору, что нужно делать. Каждая инструкция хранит в себе код операции (или «опкод») и генерирует одну инструкцию на машинном языке.

Директивы ассемблера — сообщают программе об аспектах компиляции. Они не генерируют инструкции на машинном языке.

Макросы — являются простым механизмом вставки кода.

В ассемблере на одну строку приходится один стейтмент, который должен соответствовать следующему формату:

Базовая инструкция состоит из названия инструкции ( mnemonic ) и операндов (они же «параметры»). Вот примеры типичных стейтментов ассемблера:

Первая программа

Следующая программа на языке ассемблера выведет строку Hello, world! на экран:

Результат выполнения программы:

Сборка программ

Убедитесь, что у вас установлен NASM. Запишите вашу программу в текстовом редакторе и сохраните её как hello.asm. Затем:

убедитесь, что вы находитесь в той же директории, в которой вы сохранили hello.asm;

если не было ошибок, то создастся объектный файл вашей программы под названием hello.o;

Если у вас нет возможности скомпилировать программу, например, у вас нет Linux и вы пока не хотите на него переходить, то можете использовать одну из следующих онлайн-IDE:

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

Источник

Структура программы на языке ассемблера


Глава из книги “Ассемблер для процессоров Intel Pentium”


Автор: Ю. Магда
Источник: Ассемблер для процессоров Intel Pentium
Материал предоставил: Издательство «Питер»

Опубликовано: 08.04.2006
Версия текста: 1.0

Материал этой главы посвящен вопросам организации и компоновки программного кода на языке ассемблера. Затронуты вопросы взаимодействия различных частей ассемблерной программы, организации сегментов программного кода, данных и стека в контексте различных моделей памяти. Напомню, что мы рассматриваем эти аспекты применительно к макроассемблеру MASM фирмы Microsoft, хотя многие положения действительны и для других компиляторов. Начнем с анализа сегментов. Мы уже сталкивались с этими вопросами в главе 3, сейчас же рассмотрим их более детально.

4.1. Организация сегментов

Для хорошего понимания, как работает программа на ассемблере, нужно очень четко представлять себе организацию сегментов. Применительно к процессорам Intel Pentium термин “сегмент” имеет два значения:

Физический сегмент может располагаться только по адресу, кратному 16, или, как иногда говорят, по границе параграфа. Логические сегменты тесно связаны с физическими. Каждый логический сегмент ассемблерной программы определяет именованную область памяти, которая адресуется селектором сегмента, содержащимся в сегментном регистре. Сегментированная архитектура создает определенные трудности в процессе разработки программ. Для небольших программ, меньших 64 Кбайт, программный код и данные могут размещаться в отдельных сегментах, поэтому никаких особых проблем не возникает.

При использовании 32-разрядного защищенного режима эти проблемы исчезают. Например, в плоской модели памяти (о ней мы поговорим чуть позже) для адресации программного кода и данных достаточно 32-разрядного эффективного адреса внутри непрерывной области памяти.

Логические сегменты могут содержать три основных компонента программы: программный код, данные и стек. Макроассемблер MASM обеспечивает правильное отображение этих компонентов на физические сегменты памяти, при этом сегментные регистры CS, DS и SS содержат адреса физических сегментов памяти.

4.2. Директивы управления сегментами и моделями памяти макроассемблера MASM

В макроассемблер MASM включены директивы, упрощающие определение сегментов программы и, кроме того, предполагающие те же соглашения, которые используются в языках высокого уровня Microsoft. Упрощенные директивы определения сегментов генерируют необходимый код, указывая при этом атрибуты сегментов и порядок их расположения в памяти. Везде в этой книге мы будем использовать именно упрощенные директивы определения сегментов, наиболее важные из которых перечислены далее:

Модель памяти Адресация кода Адресация данных Операционная система Чередование кода и данных
TINY NEAR NEAR MS-DOS Допустимо
SMALL NEAR NEAR MS-DOS, Windows Нет
MEDIUM FAR NEAR MS-DOS, Windows Нет
COMPACT NEAR FAR MS-DOS, Windows Нет
LARGE FAR FAR MS-DOS, Windows Нет
HUGE FAR FAR MS-DOS, Windows Нет
FLAT NEAR NEAR Windows NT, Windows 2000, Windows XP, Windows 2003 Допустимо
Таблица 4.1. Параметры моделей памяти

Все семь моделей памяти поддерживаются всеми компиляторами MASM, начиная с версии 6.1.

Модель small поддерживает один сегмент кода и один сегмент данных. Данные и код при использовании этой модели адресуются как near (ближние). Модель large поддерживает несколько сегментов кода и несколько сегментов данных. По умолчанию все ссылки на код и данные считаются дальними (far).

Модель medium поддерживает несколько сегментов программного кода и один сегмент данных, при этом все ссылки в сегментах программного кода по умолчанию считаются дальними (far), а ссылки в сегменте данных — ближними (near). Модель compact поддерживает несколько сегментов данных, в которых используется дальняя адресация данных (far), и один сегмент кода с ближней адресацией (near). Модель huge практически эквивалентна модели памяти large.

Должен заметить, что разработчик программ может явно определить тип адресации данных и команд в различных моделях памяти. Например, ссылки на команды внутри одного сегмента кода в модели large можно сделать ближними (near). Проанализируем, в каких случаях лучше всего подходят те или иные модели памяти.

Модель tiny работает только в 16-разрядных приложениях MS-DOS. В этой модели все данные и код располагаются в одном физическом сегменте. Размер программного файла в этом случае не превышает 64 Кбайт. С другой стороны, модель flat предполагает несегментированную конфигурацию программы и используется только в 32-разрядных операционных системах. Эта модель подобна модели tiny в том смысле, что данные и код размещены в одном сегменте, только 32-разрядном. Хочу напомнить, что многие примеры из этой книги разработаны именно для модели flat.

Параметр соглашение_о_вызовах используется для определения способа передачи параметров при вызове процедуры из других языков, в том числе и языков высокого уровня (C++, Pascal). Параметр может принимать следующие значения: C, BASIC, FORTRAN, PASCAL, SYSCALL, STDCALL. При разработке модулей на ассемблере, которые будут применяться в программах, написанных на языках высокого уровня, обращайте внимание на то, какие соглашения о вызовах поддерживает тот или иной язык. Более подробно соглашения о вызовах мы будем рассматривать при анализе интерфейса программ на ассемблере с программами на языках высокого уровня.

Параметр тип_ОС равен OS_DOS, и на данный момент это единственное поддерживаемое значение этого параметра.

Здесь параметр flat указывает компилятору на то, что будет использоваться 32-разрядная линейная адресация. Второй параметр c указывает, что при вызове ассемблерной процедуры из другой программы (возможно, написанной на другом языке) будет задействован способ передачи параметров, принятый в языке C. Следующий пример:

Здесь используются модель памяти large, соглашение о передаче параметров языка C и отдельный сегмент стека (регистр SS не равен DS).

В этом примере используются модель medium, соглашение о передаче параметров для Pascal и область стека, размещенная в одном физическом сегменте с данными.

4.3. Структура программ на ассемблере MASM

В следующем примере показана 16-разрядная программа на ассемблере, в которой используются упрощенные директивы ассемблера MASM:

Читайте также:  разработка какого плана в рамках организации документационного обеспечения систем управления ответ

Здесь оператор end main указывает на точку входа main в главную процедуру. Оператор end закрывает последний сегмент и обозначает конец исходного текста программы. В 16-разрядных приложениях MS-DOS можно инициализировать сегментные регистры так, чтобы они указывали на требуемый логический сегмент данных. Листинг 4.1 демонстрирует это.

Затем строка s1, адресуемая через регистры DS:DX, выводится на экран с использованием прерывания 9h функции 21h MS-DOS. Попробуйте закомментировать проанализированные две строки кода и посмотреть на результат работы программы.

Для 32-разрядных приложений шаблон исходного текста выглядит иначе:

Основное отличие от предыдущего примера — другая модель памяти (flat), предполагающая 32-разрядную линейную адресацию с атрибутом near.

Замечу, что директива SEGMENT может применяться с любой моделью памяти, не только flat. При использовании директивы SEGMENT потребуется указать компилятору на то, что все сегментные регистры устанавливаются в соответствии с моделью памяти flat. Это можно сделать при помощи директивы ASSUME:

Регистры FS и GS программами не используются, поэтому для них указывается атрибут ERROR.

Сейчас мы рассмотрим программный код 32-разрядной процедуры на ассемблере (она называется _seg_ex), в которой используются два логических сегмента данных. Процедура выполняет копирование строки src, находящейся в сегменте данных data1, в область памяти dst в сегменте данных data2 и содержит один логический сегмент программного кода (code segment).

Успокою читателей, незнакомых с принципами работы процедур (они рассмотрены далее в книге): в данном случае нас будет интересовать код внутри процедуры _seg_ex (команды, находящиеся между директивами _seg_ex proc и _seg_ex endp). Исходный текст программного кода процедуры _seg_ex представлен в листинге 4.2.

При использовании модели flat доступ к данным осуществляется по 32-разрядному смещению, поэтому смысл показанных ниже команд, загружающих адреса логических сегментов (а заодно и адреса строк src и dst) в регистры ESI и EDI, думаю, понятен:

Группа следующих команд выполняет копирование строки src в dst, при этом регистр CX содержит количество копируемых байтов:

Здесь процедура seg_ex является внешней, поэтому объявлена как extern.

Результатом выполнения программы будет строка на экране дисплея

Источник

Структура программы на ассемблере

Программирование на уровне машинных команд — это тот минимальный уровень, на котором возможно составление программ. Система машинных команд должна быть достаточной для того, чтобы реализовать требуемые действия, выдавая указания аппаратуре вычислительной машины.

Каждая машинная команда состоит из двух частей:

Машинная команда микропроцессора, записанная на языке ассемблера, представляет собой одну строку, имеющую следующий синтаксический вид:

метка команда/директива операнд(ы) ;комментарии

При этом обязательным полем в строке является команда или директива.

Метка, команда/директива и операнды (если имеются) разделяются по крайней мере одним символом пробела или табуляции.

Если команду или директиву необходимо продолжить на следующей строке, то используется символ обратный слеш: \.

По умолчанию язык ассемблера не различает заглавные и строчные буквы в написании команд или директив.

Примеры строк кода:

Метки

Метка в языке ассемблера может содержать следующие символы:

В качестве первого символа метки может использоваться точка, но некоторые компиляторы не рекомендуют применять этот знак. В качестве меток нельзя использовать зарезервированные имена Ассемблера (директивы, операторы, имена команд).

Команды

Команда указывает транслятору, какое действие должен выполнить микропроцессор. В сегменте данных команда (или директива) определяет поле, рабочую область или константу. В сегменте кода команда определяет действие, например, пересылка (mov) или сложение (add).

Директивы

Ассемблер имеет ряд операторов, которые позволяют управлять процессом ассемблирования и формирования листинга. Эти операторы называются директивами . Они действуют только в процессе ассемблирования программы и, в отличие от команд, не генерируют машинных кодов.

Операнды

Операнд – объект, над которым выполняется машинная команда или оператор языка программирования.
Команда может иметь один или два операнда, или вообще не иметь операндов. Число операндов неявно задается кодом команды.
Примеры:

Метка, команда (директива) и операнд не обязательно должны начинаться с какой-либо определенной позиции в строке. Однако рекомендуется записывать их в колонку для большего удобства чтения программы.

В качестве операндов могут выступать

Идентификаторы

Идентификаторы – последовательности допустимых символов, использующиеся для обозначения таких объектов программы, как коды операций, имена переменных и названия меток.

Правила записи идентификаторов.

Комментарии
Структура программы на ассемблере

Пример «ничего не делающей» программы на языке ассемблера:

Источник

MS-DOS и TASM 2.0. Часть 17. Константы, массивы, структуры и т.д.

Организация данных в ассемблере.

Прежде, чем переходить к рассмотрению вопроса что такое константа, массив, структура в ассемблере, поговорим о понятии абстракции.

Для упрощения написания кода необходимо преобразовать его в понятный для человека вид, желательно не в ущерб для машины. Для этого используют условности и обобщения — определённую степень абстракции. Один из простейших способов абстракции — разбивка кода и данных на части — блоки по определённым правилам и с определёнными особенностями. Затем эти блоки обзывают понятным для человека языком.

Схематичная структура кода на ассемблере.

Но для удобства программиста можно написать и так:

Опустимся по линии абстракции кода ниже. Мы уже знаем и можем назвать один из блоков кода, который имеет имя, параметры и возвращаемое значение. Этот «блок» может вызываться практически неограниченное число раз, будучи написанным один раз Вы уже догадались, что это функция.

В этой статье речь пойдёт о блоках данных. Мы рассмотрим, что такое константа, массив, структура в ассемблере, а также более редко встречающиеся: перечисление, объединение, запись с битовыми полями (запись).

Беглый обзор.

Пробежимся по понятиям в ознакомительных целях, более подробно рассмотрим вопрос потом, когда перейдём к 32 битному Windows программированию.

Константа в ассемблере.

Мы уже знаем, что значение (конкретное число) можно присвоить переменной, предварительно определив размер этой переменной в байт, слово, двойное слово и т.д.:

Константа — символ, синоним конкретного числа (выражения, строки), которое, в отличие от переменной нельзя изменить.

Для задания констант применяются обозначения:

Структура в ассемблере.

Структура в ассемблере (structure) — это совокупность переменных, объединенных одним именем. Переменные называются полями и могут быть разными по размеру. Очень удобно обращаться к данным по именам полей. Структура — основа абстракции, «блочности» кода. Понятие КЛАСС в языках высокого уровня есть не что иное, как разновидность структуры. Только в качестве полей в классе кроме данных присутствуют ещё и функции. В качестве поля в структуру может входить структура (пример — в коде).

Константы, массив и структура в ассемблере — наиболее часто используемые организованные виды данных, однако есть и другие. Если посмотреть на структуру повнимательнее, со стороны нашего подхода к программированию, как к совокупности кода и данных, то остальные виды сгруппированных данных : массив, перечисление, объединение, битовые поля — фактически являются разновидностями структуры, реализованные в целях экономии процессорного времени и объёма памяти.

Массив в ассемблере.

Массив — структура данных, хранящих значения, которые идентифицируются по индексам, начиная с нулевого индекса. Рассмотрим работу с одномерным массивом — с учётом нашего начального уровня.

Перечисление в ассемблере.

Перечисления (enum) представляет собой структуру, состоящую из именованных констант. Создана для удобства программирования в Си. При этом можно просто перечислять константы, компилятор будет присваивать им целые значения в порядке возрастания, начиная с нуля. Если присвоить полю конкретное значение, которое не совпадает с простой последовательностью, отсчёт следующих, не определённых полей будет происходить по алгоритму «+1».
enum eDirection
<
RIGHT, // по умолчанию = 0
LEFT, // = 1
DOWN=5, // = 5 — присвоили, если бы не присвоить, то DOWN==2 (предыдущее поле +1)
UP // = 6 (+1)
>;

В ассемблере перечисление (enum) как отдельный, самостоятельный тип данных не существует. При необходимости используют структуру с целочисленными полями либо просто отдельные целочисленные константы.

Объединения в ассемблере.

Объединение (union) — одна и та же область памяти, используемая как разные типы данных. Естественно, в таком случае размер объединения будет равен размеру наибольшего из значений и не равна сумме длин всех запоминаемых, как в структуре. Тип данных создавался для Си, как способ экрномии памяти компьютера (сейчас — не актуально, но ранее активно использовался в написании кода, в том числе и сетевого характера, поэтому применяется и сейчас для совместимости).

Читайте также:  hla b27 положительный это что значит у женщин в крови

После этого _union._word=1234h, а _union._byte=34h.

Записи с битовыми полями (запись).

Бит — единица данных, может содержать значение 1 или 0. Записи с битовыми полями (records) используют эту возможность.

Каждое битовое поле имеет заданную длину (в битах) и начальное значение. Размер данных типа записи равен сумме длин всех полей

Запись с битовыми полями (запись) — 32 бита.

Опять таки — удобно, экономит место и вычислительное время. Например, чтобы задать цвет точки в изображении (совокупность различных оттенков красного, зелёного, синего (RGB) или свойств окна в операционке Windows.

Не будем подробно разбирать тему, приведём пример кода.

Источник

Data ассемблер что это

Справочная система по языку Assembler

Типы данных

Рис. 1. Основные типы данных микропроцессора

Рис. 2. Основные логические типы данных микропроцессора

Отметим, что “Зн” на рис. 2 означает знаковый бит.

После всего сказанного было бы логичным возникновение у читателя вопроса: как описать эти простые типы данных ассемблера, а затем и воспользоваться ими в программе? Ведь любая программа предназначена для обработки некоторой информации, поэтому вопрос о том, как описать данные с использованием средств языка обычно встает одним из первых.

TASM предоставляет очень широкий набор средств описания и обработки данных, который вполне сравним с аналогичными средствами некоторых языков высокого уровня.

Директивы резервирования и инициализации данных простых типов имеют формат, показанный на рис. 3.

Рис. 3. Директивы описания данных простых типов

Для иллюстрации данного принципа рассмотрим листинг 1, в котором определим сегмент данных. В этом сегменте данных приведено несколько директив описания простых типов данных.

Теперь наша цель — посмотреть, как выглядит сегмент данных программы листинга 1 в памяти компьютера. Это даст нам возможность обсудить практическую реализацию обозначенного нами принципа размещения данных. Для этого запустим отладчик TD.EXE, входящий в комплект поставки TASM. Результат показан на рис. 4.

Рис. 4. Окно дампа памяти для программы листинга 1

Разберемся более подробно с тем, как определить данные этих типов в программе и организовать работу с ними.

Массивы


Описание и инициализация массива в программе


Доступ к элементам массива

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

В общем случае для получения адреса элемента в массиве необходимо начальный (базовый) адрес массива сложить с произведением индекса (номер элемента минус единица) этого элемента на размер элемента массива:

база + (индекс*размер элемента)

Этот вид адресации удобно использовать при обработке двухмерных массивов. Пример использования этой адресации мы рассмотрим далее при изучении особенностей работы с двухмерными массивами.

Напомним, что в качестве базового регистра может использоваться любой из восьми регистров общего назначения. В качестве индексного регистра также можно использовать любой регистр общего назначения, за исключением esp/sp.

В качестве примера использования масштабирования рассмотрим листинг 3, в котором просматривается массив, состоящий из слов, и производится сравнение этих элементов с нулем. Выводится соответствующее сообщение.

Заметим, что базово-индексную адресацию не возбраняется сочетать с прямой адресацией или указанием непосредственного значения. Адрес тогда будет формироваться как сумма всех компонентов.

Но имейте в виду, что масштабирование эффективно лишь тогда, когда размерность элементов массива равна 2, 4 или 8 байт. Если же размерность элементов другая, то организовывать обращение к элементам массива нужно обычным способом, как описано ранее.

Рассмотрим пример работы с массивом из пяти трехбайтовых элементов (листинг 4). Младший байт в каждом из этих элементов представляет собой некий счетчик, а старшие два байта — что-то еще, для нас не имеющее никакого значения. Необходимо последовательно обработать элементы данного массива, увеличив значения счетчиков на единицу.

Двухмерные массивы

С представлением одномерных массивов в программе на ассемблере и организацией их обработки все достаточно просто. А как быть если программа должна обрабатывать двухмерный массив? Все проблемы возникают по-прежнему из-за того, что специальных средств для описания такого типа данных в ассемблере нет. Двухмерный массив нужно моделировать. На описании самих данных это почти никак не отражается — память под массив выделяется с помощью директив резервирования и инициализации памяти.

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

Если последовательность однотипных элементов в памяти трактуется как двухмерный массив, расположенный по строкам, то адрес элемента (i, j) вычисляется по формуле

(база + количество_элементов_в_строке * размер_элемента * i+j)

Например, пусть имеется массив чисел (размером в 1 байт) mas(i, j) с размерностью 4 на 4
(i= 0. 3, j = 0. 3) :

В памяти элементы этого массива будут расположены в следующей последовательности:

23 04 05 67 05 06 07 99 67 08 09 23 87 09 00 08

Эффективный адрес mas(2, 3) = mas + 4 * 1 * 2 + 3 = mas + 11

Посмотрите на представление массива в памяти и убедитесь, что по этому смещению действительно находится нужный элемент массива.

В программе это будет выглядеть примерно так:

В качестве законченного примера рассмотрим программу поиска элемента в двухмерном массиве чисел (листинг 5). Элементы массива заданы статически.

Типовые операции с массивами

Для демонстрации основных приемов работы с массивами лучше всего подходят программы поиска или сортировки.

Рассмотрим одну такую программу, выполняющую сортировку массива по возрастанию (листинг 6).

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

Структуры

По определению структура — это тип данных, состоящий из фиксированного числа элементов разного типа.

Описать структуру в программе можно только один раз, а определить — любое количество раз.

Описание шаблона структуры

Описание шаблона структуры имеет следующий синтаксис:

Как мы уже отметили при описании шаблона, память не выделяется, так как это всего лишь информация для транслятора.

Местоположение шаблона в программе может быть поизвольным, но, следуя логике работы однопроходного транслятора, он должен быть расположен до того места, где определяется переменная с типом данной структуры. То есть при описании в сегменте данных переменной с типом некоторой структуры ее шаблон необходимо поместить в начале сегмента данных либо перед ним.

Рассмотрим работу со структурами на примере моделирования базы данных о сотрудниках некоторого отдела.
Для простоты, чтобы уйти от проблем преобразования информации при вводе, условимся, что все поля символьные.
Определим структуру записи этой базы данных следующим шаблоном:

Определение данных с типом структуры

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

Для примера определим несколько переменных с типом описанной выше структуры.

Методы работы со структурой

Рис. 5. Синтаксис адресного выражения в операторе обращения к полю структуры

Читайте также:  какой народ живет в оренбурге

Давайте представим, что сотрудников не четверо, а намного больше, и к тому же их число и информация о них постоянно меняются. В этом случае теряется смысл явного определения переменных с типом worker для конкретных личностей.
Язык ассемблера разрешает определять не только отдельную переменную с типом структуры, но и массив структур.
К примеру, определим массив из 10 структур типа worker :

Дальнейшая работа с массивом структур производится так же, как и с одномерным массивом. Здесь возникает несколько вопросов:
Как быть с размером и как организовать индексацию элементов массива?

Как выполнить копирование поля из одной структуры в соответствующее поле другой структуры? Или как выполнить копирование всей структуры? Давайте выполним копирование поля nam третьего сотрудника в поле nam пятого сотрудника:

Наличие в языке следующих двух типов данных, наверное, объясняется стремлением “хозяйки” максимально эффективно использовать рабочую площадь стола (оперативной памяти) при приготовлении еды или для размещения продуктов (данных программы).

Объединения

Объединение — тип данных, позволяющий трактовать одну и ту же область памяти как имеющую разные типы и имена.

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

Какие из этих указателей можно применять в конкретной ситуации, зависит от режима адресации ( use16 или use32 ) и режима работы микропроцессора.
Так вот, описанный в листинге 7 шаблон объединения позволяет нам облегчить формирование и использование указателей различных типов.

Когда вы будете работать в защищенном режиме микропроцессора и использовать 32-разрядные адреса, то аналогичным способом можете заполнить и использовать описанное выше объединение.

Записи

Наша “хозяйка-программист” становится все более экономной. Она уже хочет работать с продуктами на молекулярном уровне, без любых отходов и напрасных трат.
Подумаем, зачем тратить под некоторый программный индикатор со значением “включено-выключено” целых восемь разрядов, если вполне хватает одного? А если таких индикаторов несколько, то расход оперативной памяти может стать весьма ощутимым.
Когда мы знакомились с логическими командами, то говорили, что их можно применять для решения подобной проблемы. Но это не совсем эффективно, так как велика вероятность ошибок, особенно при составлении битовых масок.

Запись — структурный тип данных, состоящий из фиксированного числа элементов длиной от одного до нескольких бит.
При описании записи для каждого элемента указывается его длина в битах и, что необязательно, некоторое значение.
Суммарный размер записи определяется суммой размеров ее полей и не может быть более 8, 16 или 32 бит.
Если суммарный размер записи меньше указанных значений, то все поля записи “прижимаются” к младшим разрядам.

Компилятор TASM, кроме стандартных средств обработки записей, поддерживает также и некоторые дополнительные возможности их обработки.

Описание записи

Описание шаблона записи имеет следующий синтаксис (рис. 6):

Здесь:
представляет собой последовательность описаний отдельных элементов записи согласно синтаксической диаграмме (см. рис. 6):

Рис. 6. Синтаксис описания шаблона записи

При описании шаблона память не выделяется, так как это всего лишь информация для транслятора ассемблера о структуре записи.
Так же, как и для структур, местоположение шаблона в программе может быть любым, но при этом необходимо учитывать логику работы однопроходного транслятора.

Определение экземпляра записи

Для использования шаблона записи в программе необходимо определить переменную с типом данной записи, для чего применяется следующая синтаксическая конструкция (рис. 7):

Рис. 7. Синтаксис описания экземпляра записи

Анализируя эту синтаксическую диаграмму, можно сделать вывод, что инициализация элементов записи осуществляется достаточно гибко. Рассмотрим несколько вариантов инициализации.

Если вы составите и исследуете в отладчике тестовый пример с данным определением записи, то увидите, что все поля переменной типа запись flag обнуляются. Это происходит несмотря на то, что в определении записи заданы начальные значения полей.

Если требуется частичная инициализация элементов, то они заключаются в угловые ( и > ) или фигурные ( < и >) скобки.
Различие здесь в том, что в угловых скобках элементы должны быть заданы в том же порядке, что и в определении записи. Если значение некоторого элемента совпадает с начальным, то его можно не указывать, но обязательно обозначить его запятой. Для последних элементов идущие подряд запятые можно опустить.
К примеру, согласиться со значениями по умолчанию можно так:

Изменить значение поля i2 можно так:

Применяя фигурные скобки, также можно указать выборочную инициализацию полей, но при этом необязательно обозначать запятыми поля, со значениями по умолчанию которых мы согласны:

Работа с записями

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

Выделение элемента записи:

В результате этих действий элемент записи будет локализован в начале рабочего регистра и далее с ним можно производить любые действия.

Работа с элементом записи:

Как мы уже выяснили, с элементами записи производятся любые действия, как над обычной двоичной информацией.
Единственное, что нужно отслеживать, — это размер битового поля. Если, к примеру, размер поля увеличится, то впоследствии может произойти случайное изменение соседних полей битов. Поэтому желательно исключить изменение размера поля.

Помещение измененного элемента на его место в запись:

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

Записи: дополнительные возможности обработки

Понимая важность для эффективного программирования такого типа данных, как запись, разработчики транслятора TASM, начиная с версии 3.0, включили в систему его команд две дополнительные команды на правах директив.
Последнее означает, что эти команды внешне имеют формат обычных команд ассемблера, но после трансляции они приводятся к одной или нескольким машинным командам.
Введение этих команд в язык TASM повышает наглядность работы с записями, оптимизирует код и уменьшает размер программы.
Эти команды позволяют скрыть от программиста действия по выделению и установке отдельных полей записи (мы их обсуждали выше).

Для установки значения некоторого поля записи используется команда setfield с синтаксисом:

Для выборки значения некоторого поля записи используется команда getfield с синтаксисом:

Важно отметить, что setfield не производит предварительной очистки элемента, в результате после логического сложения командой or возможно наложение старого содержимого элемента и нового устанавливаемого значения. Поэтому требуется предварительно подготовить поле в записи путем его обнуления.

В качестве примера применения команд setfield и getfield рассмотрим листинг 9.

Запомните это описание. Когда вы освоите работу с макрокомандами и в дальнейшей своей работе столкнетесь с необходимостью работать с регистром флагов, то у вас буквально “зачешутся” руки, чтобы написать соответствующую макрокоманду. Эта макрокоманда, если вы не забудете хорошо ее оттестировать, избавит вас от многих трудно обнаруживаемых ошибок.

Источник

Сказочный портал