Описание простых типов данных асемблера

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

Начнем обсуждение с правил описания простых типов данных, которые являются базовыми для описания более сложных типов. Для описания простых типов данных в программе используются специальные директивы резервирования и инициализации данных, которые по сути являются указаниями транслятору на выделение определенного объема памяти. Если проводить аналогию с языками высокого уровня, то директивы резервирования и инициализации данных являются определениями переменных. Машинного эквивалента этим директивам нет; просто транслятор, обрабатывая каждую такую директиву, выделяет необходимое количество байт памяти и при необходимости инициализирует эту область некоторым значением. Директивы резервирования и инициализации данных простых типов имеют формат, показанный на рис. 5.17.

На рис. 5.17 использованы следующие обозначения.

§ ? показывает, что содержимое поля не определено, то есть при задании директивы с таким значением выражения содержимое выделенного участка физической памяти изменяться не будет. Фактически создается неинициализированная переменная;

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

§ выражение — итеративная конструкция с синтаксисом, описанным на рис. 5.17. Эта конструкция позволяет повторить последовательное занесение в физическую память выражения в скобках п раз.

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

Описание простых типов данных асемблера

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

На рис. 5.17 представлены следующие поддерживаемые TASM директивы ре-зервирования и инициализации данных:

§ db — резервирование памяти для данных размером 1 байт;

§ dw — резервирование памяти для данных размером 2 байта;

§ dd — резервирование памяти для данных размером 4 байта;

§ df — резервирование памяти для данных размером 6 байт;

§ dp — резервирование памяти для данных размером 6 байт;

§ dq — резервирование памяти для данных размером 8 байт;

§ dt — резервирование памяти для данных размером 10 байт.

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

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

Описание простых типов данных асемблера

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

Введем код из листинга 5.2 в файл с названием prg_5_2.asm. Как мы договорились раньше, все манипуляции с файлом будем производить в директории work, где уже содержатся все необходимые для компиляции, компоновки и отладки файлы пакета TASM.

Запустим процесс трансляции файла следующей командой:

tasm.exe /zi prg_5_2.asm , , ,

После устранения синтаксических ошибок запустим процесс компоновки объектного файла:

tlink.exe /v prg_5_2.obj

Теперь можно производить отладку:

td prg_5_2.exe

Если все было сделано правильно, то в отладчике откроется окно Module с исходным текстом программы. Для того чтобы с помощью отладчика просмотреть область памяти, содержащую наш сегмент данных, необходимо открыть окно Dump. Это делается с помощью команды главного меню View| Dump.

Но одного открытия окна недостаточно; нужно еще настроить его на адрес начала сегмента данных. Этот адрес должен содержаться в сегментном регистре ds, но, как сказано выше, перед началом выполнения программы адрес в ds не соответствует началу сегмента данных. Нужно перед первым обращением к любому символическому имени произвести загрузку действительного физического адреса сегмента данных. Обычно это действие не откладывают в долгий ящик и производят первыми двумя командами в сегменте кода. Действительный физический адрес сегмента данных извлекают как значение предопределенной переменной @data. В нашей программе эти действия выполняют команды

mov ах,@data

mov ds,ах

Для того чтобы посмотреть содержимое нашего сегмента данных, нужно остановить выполнение программы после этих двух команд. Это можно сделать, если перевести отладчик в пошаговый режим с помощью клавиш F7 или F8. Нажмите два раза F8. Теперь можно открыть окно Dump.

В окне Dump вызовите контекстное меню, щелкнув правой кнопкой мыши. В появившемся контекстном меню выберите команду Goto. Появится диалоговое окно, в котором нужно ввести начальный адрес памяти, начиная с которого будет выводиться информация в окне Dump. Синтаксис задания этого адреса должен соответствовать синтаксису задания адресного операнда в программе на ассемблере (см. начало этого урока). Мы бы хотели увидеть содержимое памяти для нашего сегмента данных, начиная с его начала, поэтому введем ds: 0000. Для удобства, если сегмент достаточно велик, это окно можно распахнуть на весь экран. Для этого нужно щелкнуть на символе в правом верхнем углу окна Dump. Вид экрана показан на рис. 5.18.

Обсудим рис. 5.18. На нем можно видеть данные нашего сегмента в двух представлениях: шестнадцатеричном и символьном. Видно, что со смещением 0000 расположены символы, входящие в строку message. Она занимает 34 байта. После нее следует байт, имеющий в сегменте данных символическое имя perem_1, содержимое этого байта 0ffh. Теперь обратите внимание на то, как размещены в памяти байты, входящие в слово, обозначенное символическим именем реrem_2.

Сначала следует байт со значением 7fh, а затем со значением 3ah. Как видите, в памяти действительно сначала расположен младший байт значения, а затем старший. Теперь посмотрим и самостоятельно проанализируем размещение байтов для поля, обозначенного символическим именем perem_3. Оставшуюся часть сегмента данных можем теперь проанализировать самостоятельно. Остановимся лишь на двух специфических особенностях использования директив резервирования и инициализации памяти. Речь идет о случае использования в поле операндов директив dw и dd символического имени из поля имя этой или другой директивы резервирования и инициализации памяти. В нашем примере сегмента данных это директивы с именами adr и adr_full. Когда транслятор встречает директивы описания памяти с подобными операндами, то он формирует в памяти значения адресов тех переменных, чьи имена были указаны в качестве операндов. В зависимости от директивы, применяемой для получения такого адреса, формируется либо полный адрес (директива dd) в виде двух байтов сегментного адреса и двух байтов смещения, либо только смещение (директива dw). Найдите в дампе на рис. 5.18 поля, соответствующие именам adr и adr_full, и проанализируйте их содержимое.

Описание простых типов данных асемблера

Puc. 5.18. Окно дампа памяти

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

1. Сегмент (seg) — адрес начала сегмента, содержащего переменную.

2. Смещение (offset) в байтах от начала сегмента с переменной.

3. Тип (type) — определяет количество памяти, выделяемой переменной в соответствии с директивой объявления переменной.

Получить и использовать значение этих атрибутов в программе можно с помощью рассмотренных нами выше операторов ассемблера seg, offset и type.

Подведем некоторые итоги:

u Программа на ассемблере, отражая особенности архитектуры микропроцессора, состоит из сегментов — блоков памяти, допускающих независимую адресацию.

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

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

u Операнды в команде могут быть выражениями.

u Исходный текст программы разбивается на сегменты с помощью директив сегментации, которые делятся на стандартные, поддерживаемые всеми транс-ляторами ассемблера, и упрощенные, поддерживаемые транслятором TASM.

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

u Существует два режима работы TASM: MASM и IDEAL. Назначение режима MASM — обеспечить полную совместимость с транслятором MASM фирмы Microsoft. Назначение режима IDEAL — упростить синтаксис конструкций языка, повысить эффективность и скорость работы транслятора.

u TASM поддерживает разнообразные типы данных, которые делятся на простые (базовые) и сложные. Простые типы служат как бы «кирпичиками» для построения сложных типов данных.

u Директивы описания простых типов данных позволяют зарезервировать и при необходимости инициализировать области памяти заданной длины.

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

Assembler #1: Введение


Похожие статьи.

Понравилась статья? Поделиться с друзьями: