assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 64
Текст из файла (страница 64)
Постарайтесь внимательноотнестись к анализу этой программы. Основная идея здесь в том, что указатель напамять, формируемый программой, может быть представлен в виде:16-разрядного смещения;32-разрядного смещения;пары из 16-разрядного смещения и 16-разрядной сегментной составляющейадреса;ii пары из 32-разрядного смещения и 16-разрядного селектора.Какие из этих указателей можно применять в конкретной ситуации, зависит отрежима адресации (use!6 или use32) и режима работы процессора. Шаблон объединения, описанный в листинге 13.6, позволяет упростить формирование и использование указателей различных типов.Листинг 13.6.
Пример использования объединенияmasmmodelstack.586Psmall256pnt strucunionoffs_16 dwoffs_32 ddendssegmdwends.datapoint unionструктура pnt, содержащая вложенное объединениеописание вложенного в структуру объединенияконец описания объединенияконец описания структурыопределение объединения,содержащего вложенную структуруoff_16 dw ?off_32 dd ?point_16pnt <>point_32pnt <>point endstst db "Строка для тестирования"adr_datapoint <> определение экземпляра объединения.codemain:mov ax,@datamov ds.axmov ax.seg tst;записать адрес сегмента строки tst в поле структуры adr_datamov adr_data.point_16.segm,ax;когда понадобится, можно извлечь значение из этого поля обратно,;к примеру, в регистр Ьх:mov bx,adr_data.point_16.segm;формируем смещение в поле структуры adr_datamov ax,offset tst;смещение строки в ахmov adr_data.point_16.offs_16,axпродолжение^286Глава 13.
Сложные структуры данныхЛ истинг 13.6 (продолжение).•аналогично, когда понадобится, можно извлечь;значение из этого поля:mov bx,adr_data.point_16.offs_16exit:mov ax,4c00hint 21hend mainКогда вы будете работать в защищенном режиме процессора и использовать32-разрядные адреса, то аналогичным способом можете заполнить и задействоватьописанное ранее объединение.ЗаписиНа практике довольно часто возникает необходимость работы с различными программными индикаторами со значениями «включено—выключено». Минимальная величина для операций с памятью — байт. А для программного индикаторадостаточно одного бита. То есть из восьми разрядов нужно задействовать всегоодин. При большом количестве таких индикаторов расход оперативной памятиможет быть весьма ощутимым.Когда мы знакомились с логическими командами, то говорили, что их можноприменять для решения подобной проблемы.
Но это не совсем эффективно, таккак велика вероятность ошибок, особенно при составлении битовых масок. Компиляторы TASM и MASM предоставляют в распоряжение программиста специальный тип данных, использование которого помогает решить проблему работыс битами более эффективно. Речь идет о специальном типе данных — записях. Запись — структурный тип данных, состоящий из фиксированного числа элементовдлиной от одного до нескольких битов.При описании записи для каждого элемента указывается его длина в битах и,что необязательно, некоторое значение. Суммарный размер записи определяетсясуммой размеров ее полей и не может быть более 8,16 или 32 битов.
Если суммарный размер записи меньше указанных значений, то все поля записи «прижимаются» к младшим разрядам.Использование записей в программе, так же как и структур, организуется в триэтапа.1. Задание шаблона записи, то есть определение набора битовых полей, их длини, при необходимости, инициализация полей.2. Определение экземпляра записи. Так же как и для структур, этот этап подразумевает инициализацию конкретной переменной типом заранее определеннойс помощью шаблона записи.3. Организация обращения к элементам записи.Описание записиОписание шаблона записи имеет следующий синтаксис:имя записи R E C O R D <описание элементов>Записи287Здесь -«описание элементов> представляет собой последовательность описанийотдельных элементов записи согласно синтаксической диаграмме (рис.
13.2).—| Имя записи^ RECORD Ы Имя поля|-(Т)-Рис. 13.2. Синтаксис описания шаблона записиПри описании шаблона память не выделяется, так как это всего лишь информация для транслятора ассемблера о структуре записи. Так же как и для структур,местоположение шаблона в программе может быть любым, но при этом необходимо учитывать логику работы однопроходного транслятора.Определение экземпляра записиДля использования шаблона записи в программе необходимо определить переменную с типом данной записи, для чего применяется синтаксическая конструкция,показанная на рис.
13.3.Имя переменной |-| Имя записи1L Имя поля г©- ВыражениеJ>Г71Рис. 13.3. Синтаксис описания экземпляра записиАнализируя эту синтаксическую диаграмму, можно сделать вывод, что инициализация элементов записи осуществляется довольно гибко. Рассмотрим нескольковариантов инициализации.Если инициализировать поля не требуется, то дстаточно указать символ ? (вопрос) при определении экземпляра записи:iotest, record 11:1,12:2=11,13:1,14:2=11,15:2=00flagiotest?Если составить тестовый пример с таким определением записи, то в отладчикеможно увидеть, что все поля переменной типа запись flag обнуляются.
Это происходит несмотря на то, что в определении записи заданы начальные значенияполей.Если требуется частичная инициализация элементов, то они заключаютсяв угловые (< и >) или фигурные ({ и }) скобки. Различие здесь в том, что в угловых288Глава 13. Сложные структуры данныхскобках элементы должны быть заданы в том же порядке, что и в определениизаписи. Если значение некоторого элемента совпадает с начальным, то его можноне указывать, но обязательно обозначить запятой. Для последних элементов идущие подряд запятые можно опустить.К примеру, согласиться со значениями по умолчанию можно так:iotest record 1 1 : 1 , 1 2 : 2 = 1 1 , 1 3 : 1 , 1 4 : 2 = 1 1 , 1 5 : 2 = 0 0flagiotest <> ;согласились со значением по умолчаниюИзменить значение поля 12 можно так:iotest record 1 1 : 1 , 1 2 : 2 = 1 1 , 1 3 : 1 , 1 4 : 2 = 1 1 , 1 5 : 2 = 0 0flagiotest <,10,> ; переопределили 12Применяя фигурные скобки, можно провести также выборочную инициализацию полей, но при этом обозначать запятыми поля, со значениями по умолчаниюкоторых мы согласны, не обязательно:iotest record 11:1,12:2=11,13:1,14:2=11,15:2=00flagiotest{12=10} ;переопределили 12, не обращая;внимания на порядокследования других компонентов записиРабота с записямиКак организовать работу с отдельными элементами записи? Обычные механизмыадресации здесь бессильны, так как они работают на уровне ячеек памяти, то естьбайтов, а не отдельных битов.
Здесь программисту нужно приложить некоторыеусилия. Прежде всего, для понимания проблемы нужно усвоить несколько моментов.II Каждому имени элемента записи ассемблер присваивает числовое значение,равное количеству сдвигов вправо, которые нужно произвести для того, чтобыэтот элемент оказался «прижатым» к началу ячейки.
Это дает нам возможностьлокализовать его и работать с ним. Но для этого нужно знать длину элементав битах.ii Сдвиг вправо производится с помощью команды сдвига SHR.•Ассемблер содержит оператор WIDTH, который позволяет узнать размер элементазаписи в битах или полностью размер записи.
Варианты применения оператораWIDTH:Р width имя_элемента_записи — значением оператора будет размер элементав битах;П width имя_экземпляра_записи или width имя_типа_записи — значением оператора будет размер всей записи в битах.Например,mov al,width 12IDOV ax,width iotestж Ассемблер содержит оператор MASK, который позволяет локализовать биты нужного элемента записи. Эта локализация производится путем создания маски,Записи289размер которой совпадает с размером записи. В этой маске должны быть обнулены биты во всех позициях, за исключением тех, которые занимает элементв записи.•Сами действия по преобразованию элементов записи производятся с помощьюлогических команд.Подчеркнем еще раз то обстоятельство, что непосредственное обращение к конкретному элементу записи невозможно.
Для этого нужно сначала выделить его,сдвинуть при необходимости к младшим разрядам, выполнить требуемые действияи поместить обратно на свое место в записи. Поэтому, чтобы вам каждый раз «неизобретать велосипед», далее мы опишем типовые алгоритмы осуществления этихопераций над элементами записи.
Вам останется лишь оформить эти алгоритмыв виде кода соответствии с требованиями конкретной задачи.Для выделения элемента записи требуется выполнить описанную далее процеДУРУ1. Поместить запись во временную память — регистр (8-, 16- или 32-разрядныйв зависимости от размера записи).2. Получить битовую маску, соответствующую элементу записи, с помощью оператора MASK.3. Локализовать биты в регистре с помощью маски и команды AND.4. Сдвинуть биты элемента к младшим разрядам регистра командой SHR.
Числоразрядов для сдвига получить с использованием имени элемента записи.В результате этих действий элемент записи будет локализован в начале рабочего регистра, и далее с ним можно производить любые действия (см. далее).В ходе предыдущих рассуждений мы показали, что с элементами записи производятся любые действия, как с обычной двоичной информацией. Единственное,что нужно отслеживать, — это размер битового поля.
Если, к примеру, размер поляувеличится, то впоследствии может произойти случайное изменение соседних полей битов. Поэтому желательно на этапе проектирования предусматривать все варианты функционирования программы с тем, чтобы исключить любые измененияразмеров полей.Измененный элемент помещается на его место в запись следующим образом.1. Используя имя элемента записи в качестве счетчика сдвигов, сдвинуть влевобиты элемента записи.2. Если вы не уверены в том, что разрядность результата преобразований не превысила исходную, можно выполнить «обрезание» лишних битов, используякоманду AND и маску элемента.3. Подготовить исходную запись к вставке измененного элемента путем обнуления битов в записи на месте этого элемента. Это можно сделать наложениемкомандой AND инвертированной маски элемента записи на исходную запись.4. С помощью команды OR наложить значение в регистре на исходную запись.В качестве примера рассмотрим листинг 13.7, в котором поле 12 в записи iotestобнуляется.10 Зак.
256290Глава 13. Сложные структуры данныхЛистинг 13.7. Работа с полем записи;prg_13_7.asmmasmmodelsmallstack 256iotest record i 1 : 1 , 1 2 : 2 = 1 1 . 1 3 : 1 , 1 4 : 2 = 1 1 , 1 5 : 2 = 0 0.dataflagiotest <>.codemain:mov ax,@datamov ds.axmov al.mask i2shr al,i2;биты i2 в начале ахand al,0fch;обнулили i2;помещаем i2 на местоshl -al,i2mov Ы,[flag]xor bl.mask i2 ;сбросили i2or bl.al;наложилиexi t:mov ax,4c00hстандартный выходint 21hend main;конец программыВ заключение стоит еще раз проанализировать приведенные сведения о записях и особенностях работы с ними.