4499

Записи в языке ассемблер

Лекция

Информатика, кибернетика и программирование

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

Русский

2012-11-21

40.08 KB

5 чел.

Записи в языке ассемблер

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

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

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

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

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

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

Суммарный размер записи определяется суммой размеров ее полей и не может быть более 8, 16 или 32 бит.

Если суммарный размер записи меньше указанных значений, то все поля записи “прижимаются” к младшим разрядам.

Использование записей в программе, так же, как и структур, организуется в три этапа:

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

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

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

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

имя_записи RECORD <описание элементов>

Здесь:

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

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

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

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

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

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

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

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

Если инициализировать поля не требуется, то достаточно указать ? при определении экземпляра записи:

...

iotest record

i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00

 ...

flag iotest ?

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

Если требуется частичная инициализация элементов, то они заключаются в угловые (< и >) или фигурные ({ и }) скобки.

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

К примеру, согласиться со значениями по умолчанию можно так:

iotest record

i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00

...

flag iotest <> ;согласились со значением по умолчанию

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

iotest record

i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00

...

flag iotest <,10,> ; переопределили i2

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

iotest record

i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00

...

flag iotest {i2=10} ;переопределили i2, не обращая внимания на порядок

;следования других компонентов записи

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

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

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

  1.  Каждому имени элемента записи ассемблер присваивает числовое значение, равное количеству сдвигов вправо, которые нужно произвести для того, чтобы этот элемент оказался “прижатым” к началу ячейки. Это дает нам возможность локализовать его и работать с ним. Но для этого нужно знать длину элемента в битах.
  2.  Сдвиг вправо производится с помощью команды сдвига shr.
  3.  Ассемблер содержит оператор width, который позволяет узнать размер элемента записи в битах или полностью размер записи. Варианты применения оператора width:

width имя_элемента_записи ;значением оператора будет размер элемента в битах.

width имя_экземпляра_записи

или

width имя_типа_записи ;значением оператора будет размер всей записи в битах.

 mov al,width i2

...

mov ax,width iotest

  1.  Ассемблер содержит оператор mask, который позволяет локализовать биты нужного элемента записи. Эта локализация производится путем создания маски, размер которой совпадает с размером записи. В этой маске обнулены биты на всех позициях, за исключением тех, которые занимает элемент в записи.
  2.  Сами действия по преобразованию элементов записи производятся с помощью логических команд.

Теперь у вас есть вся информация о средствах ассемблера для работы с записями.

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

Ваша задача — закодировать эти алгоритмы тем или иным способом в соответствии с требованиями задачи.

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

  1.  Поместить запись во временную память — регистр (8, 16 или 32-битный в зависимости от размера записи).
  2.  Получить битовую маску, соответствующую элементу записи, с помощью оператора mask.
  3.  Локализовать биты в регистре с помощью маски и команды and.
  4.  Сдвинуть биты элемента к младшим разрядам регистра командой shr. Число разрядов для сдвига получить с использованием имени элемента записи.

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

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

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

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

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

  1.  Используя имя элемента записи в качестве счетчика сдвигов, сдвинуть влево биты элемента записи.
  2.  Если вы не уверены в том, что разрядность результата преобразований не превысила исходную, можно выполнить “обрезание” лишних битов, используя команду and и маску элемента.
  3.  Подготовить исходную запись к вставке измененного элемента путем обнуления битов в записи на месте этого элемента. Это можно сделать путем наложения командой and инвертированной маски элемента записи на исходную запись.
  4.  С помощью команды or наложить значение в регистре на исходную запись.

В качестве примера рассмотрим листинг 8, который обнуляет поле i2 в записи iotest.

Листинг 8. Работа с полем записи

;prg_12_7.asm

masm

model small

stack 256

iotest record i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00

.data

flag iotest <>

.code

main:

mov ax,@data

mov ds,ax

mov al,mask i2

shr al,i2 ;биты i2 в начале ax

 and al,0fch ;обнулили i2

;помещаем i2 на место

 shl al,i2

mov bl,[flag]

xor bl,mask i2 ;сбросили i2

or bl,al ;наложили

exit:

 mov ax,4c00h ;стандартный выход

int 21h

end main  ;конец программы

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

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

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

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

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

Эти команды позволяют скрыть от программиста действия по выделению и установке отдельных полей записи (мы их обсуждали выше).

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

setfield имя_элемента_записи назначение,регистр_источник

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

getfield имя_элемента_записи регистр_назначение, источник

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

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

  1.  сдвиг содержимого регистр_источник влево на количество разрядов, соответствующее расположению элемента в записи;
  2.  логическую операцию or над операндами назначение и регистр_источник. Результат операции помещается в операнд назначение.

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

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

В регистр, указанный операндом регистр_назначение, помещается результат работы команды — значение элемента записи.

Интересная особенность связана с регистр_назначение. Команда getfield всегда использует 16-битный регистр, даже если вы укажете в этой команде имя 8-битного регистра.

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

Листинг 9. Работа с полями записи

;prg_12_8.asm

masm

model small

stack 256

iotest record

i1:1,i2:2=11,i3:1,i4:2=11,i5:2=00

.data

flag iotest <>

.code

main:

mov ax,@data

mov ds,ax

mov al,flag

mov bl,3

setfield i5 al,bl

xor bl,bl

getfield i5 bl,al

mov bl,1

setfield i4 al,bl

setfield i5 al,bl

exit:

mov ax,4c00h ;стандартный выход

int 21h

end main ;конец программы

Результат работы команд setfield и getfield удобнее всего изучать в отладчике.

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

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

Это описание регистра eflags. Для удобства мы разбили это описание на три части:

  1.  eflags_1_7 — младший байт eflags/flags;
  2.  eflags_8_15 — второй байт eflags/flags;
  3.  eflags_h — старшая половина eflags.

eflags_l_7 record

sf7:1=0,zf6:1=0,c5:1=0,af4:1=0,c3:1=0,pf2:1=0,c1:=1,cf0:1=0

eflags_l_15 record

c15:1=0,nt14:1=0,iopl:2=0,of11:1=0,df10:1=0,if9:1=1,tf8:1=0

eflags_h record

c:13=0,ac18:1=0,vm17:1=0,rf16:1=0

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


 

А также другие работы, которые могут Вас заинтересовать

32758. Гидродинамика. Линии тока. Уравнение Бернулли 61 KB
  Гидродинамика раздел физики сплошных сред изучающий движение идеальных и реальных жидкости и газа. Если движение жидкости не содержит резких градиентов скорости то касательными напряжениями и вызываемым ими трением можно пренебречь и при описании течения. Если вдобавок малы градиенты температуры то можно пренебречь и теплопроводностью что и составляет приближение идеальной жидкости. В идеальной жидкости таким образом рассматриваются только нормальные напряжения которые описываются давлением.
32759. Ламинарное и турбулентное течение жидкости. Сила вязкого трения в жидкости. Число Рейнольдса. Формула Пуазейля 42 KB
  Число Рейнольдса. Ламинарное течение возможно только до некоторого критического значения числа Рейнольдса после которого оно переходит в турбулентное. Критическое значение числа Рейнольдса зависит от конкретного вида течения течение в круглой трубе обтекание шара и т. Число Рейнольдса Число Рейнольдса безразмерное соотношение которое как принято считать определяет ламинарный или турбулентный режим течения жидкости или газа.
32760. Термодинамический метод исследования. Термодинамические параметры. Равновесные состояния и процессы, их изображение на термодинамических диаграммах 40 KB
  Равновесные состояния и процессы их изображение на термодинамических диаграммах. Состояние системы задается термодинамическими параметрами параметрами состояния. Обычно в качестве параметров состояния выбирают: объем V м3; давление Р Па Р=dFn dS где dFn модуль нормальной силы действующей на малый участок поверхности тела площадью dS 1 Па=1 Н м2; термодинамическую температуру Т К Т=273. Под равновесным состоянием понимают состояние системы у которой все параметры состояния имеют определенные значения не изменяющиеся с...
32761. Вывод уравнения молекулярно-кинетической теории идеальных газов для давления и его сравнения с уравнением Клайперона-Менделеева 59.5 KB
  Основное уравнение молекулярнокинетической теории идеального газа Это уравнение связывает макропараметры системы – давление p и концентрацию молекулс ее микропараметрами – массой молекул их средним квадратом скорости или средней кинетической энергией: Вывод этого уравнения основан на представлениях о том что молекулы идеального газа подчиняются законам классической механики а давление – это отношение усредненной по времени силы с которой молекулы бьют по стенке к площади стенки. Учитывая связь между концентрацией молекул в газе и его...
32762. Средняя кинетическая энергия молекул. Молекулярно-кинетическое толкование абсолютной температуры. Число степеней свободы. Закон равномерного распределения энергии по степеням свободы молекул 51 KB
  Число степеней свободы. Закон равномерного распределения энергии по степеням свободы молекул. Число степени свободы молекул. Закон равномерного распространения энергии по степеням свободы молекул.
32763. Работа газа при изменении его объёма. Количество теплоты. Теплоёмкость. Первое начало термодинамики 16.59 KB
  Количество теплоты. Количество теплоты мера энергии переходящей от одного тела к другому в данном процессе. Количество теплоты является одной из основных термодинамических величин. Количество теплоты является функцией процесса а не функцией состояния то есть количество теплоты полученное системой зависит от способа которым она была приведена в текущее состояние.
32764. Приминение первого начала термодинамики к изопроцессам и адиабатному процессу идеального газа. Зависимость теплоёмкости идеального газа от вида процесса 88 KB
  Приминение первого начала термодинамики к изопроцессам и адиабатному процессу идеального газа. Зависимость теплоёмкости идеального газа от вида процесса. Тогда для произвольной массы газа получим Q=dU=mCvT M Изобарный процесс p=const. При изобарном процессе работа газа при расширении объема от V1 до V2 равна и определяется площадью прямоугольника.
32765. Работа, совершаемая идеальным газом в различных процессах 32 KB
  Работа совершенная идеальным газом в изотермическом процессе равна где число частиц газа температура и объём газа в начале и конце процесса постоянная Больцмана. Работа совершаемая газом при адиабатическом расширении численно равная площади под кривой меньше чем при изотермическом процессе. Работа совершаемая газом при изобарном процессе при расширении или сжатии газа равна = PΔV. Работа совершаемая при изохорном процессе равна нулю т.
32766. Адиабатный процесс. Уравнение Пуассона для адиабатного процесса 28 KB
  Уравнение Пуассона для адиабатного процесса. Уравнение адиабаты уравнение Пуассона.18 после соответствующих преобразований получим уравнение адиабаты: TVg1 = const или pVg = const.20 Уравнение 13.