assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 39
Текст из файла (страница 39)
Это такназываемая зона. Следовательно, диапазон представления десятичного неупакованного числа в одном байте составляет от 0 до 9.Как описать двоично-десятичные числа в программе? Для этого можно использовать только две директивы описания и инициализации данных — DB и DT. Воз-Обзор169Упакованное десятичное число 5674304:0.5 6.7 4.3 0 40000 0101 0110 0111 0100 0011 0000 0100Неупакованное десятичное число 9985784:0 9 0 9 0 8 0 5 0 7°,8040000 1001 0000 1001 0000 1000 0000 ! 01 01 0000 0111 0000 1000 0000 0100I' Зона"Рис. 8.3.
Представление BCD-чиселможность применения только этих директив для описания BCD-чисел обусловлена тем, что к таким числам также применим принцип «младший байт по младшемуадресу», что, как мы увидим далее, очень удобно для их обработки. И вообще, прииспользовании такого типа данных, как BCD-числа, порядок описания этих чиселв программе и алгоритм их обработки — это дело вкуса и личных пристрастий программиста, что станет более ясным после того, как мы далее рассмотрим основыРис.
8.4. Дамп памяти для сегмента данных листинга 8.2170Глава 8. Арифметические командыработы с BCD-числами. К примеру, приведенная в сегменте данных листинга 8.2последовательность описаний BCD-чисел будет выглядеть в памяти так, как показано на рис.
8.4.Листинг 8.2. BCD-числа;prg_8_2.asmmasmmodelsmallstack256.dataper_ldb 2 , 3 , 4 , 6 , 8 , 2per_3dt 9875645.codemain:mov ax,@datamov d s . a xexit:mov ax,4c00hint 21hend main;сегмент данныхнеупакованное BCD-число 286432;упакованное BCD-число 9875645;сегмент кода;точка входа в программу;связываем регистр dx с сегментом;данных через регистр ах;посмотрите в отладчике дамп сегмента данныхстандартный выход;конец программыПосле столь подробного обсуждения форматов данных, с которыми работаютарифметические операции, можно приступить к рассмотрению средств их обработки на уровне системы команд процессора.Арифметические операции над целымидвоичными числамиВ данном разделе мы рассмотрим особенности каждого из четырех основных арифметических действий для целых двоичных чисел со знаком и без знака. Дополнительные сведения о возможностях ассемблера по обработке целых двоичных чисел можно получить в [8].Сложение двоичных чисел без знакаПроцессор выполняет сложение операндов по правилам сложения двоичных чисел.
Проблем не возникает до тех пор, пока значение результата не превышает размерности поля операнда (см. табл. 8.1). Например, при сложении операндов размером в байт результат не должен превышать 255. Если это происходит, то результатоказывается неверен. Рассмотрим, почему. К примеру, выполним сложение: 254 ++ 5 = 259 в двоичном виде:11111110 + 0000101 - 1 00000011.Результат вышел за пределы восьми битов, и правильное его значение укладывается в 9 битов, а в 8-разрядном поле операнда осталось значение 3, что, конечно,неверно.
В процессоре подобный исход сложения прогнозируется, и предусмотрены специальные средства для фиксации подобных ситуаций и их обработки. Так,для фиксации ситуации выхода за разрядную сетку результата, как в данном случае, предназначен флаг переноса CF. Он располагается в бите 0 регистра флаговEFLAGS/FLAGS. Именно установкой этого флага фиксируется факт переноса единицы из старшего разряда операнда. Естественно, что программист должен предусматривать возможность такого исхода операции сложения и средства для кор-Арифметические операции над целыми двоичными числами171ректировки. Это предполагает включение фрагментов кода после операции сложения, в которых анализируется состояние флага CF. Этот анализ можно провестиразличными способами.
Самый простой и доступный — использовать командуусловного перехода JC. Эта команда в качестве операнда имеет имя метки в текущем сегменте кода. Переход на метку осуществляется в случае, если в результатеработы предыдущей команды флаг CF установился в 1. Команды условных переходов будут рассматриваться в главе 10.Если теперь посмотреть на рис. 8.1, то видно, что в системе команд процессораимеются три команды двоичного сложения:Ж команда инкремента, то есть увеличения значения операнда на 1:inc операндШ команда сложения (операнд_1 = операнд_1 + операнд_2):add операнд_1,операнд_2^ команда сложения с учетом флага переноса CF (операнд_1 =• операнд_1 + операнд_2+ значение_СР):adc операнд_1,операнд_2Обратите внимание на последнюю команду — это команда сложения, учитывающая перенос единицы из старшего разряда.
Механизм появления такой единицымы уже рассмотрели. Таким образом, команда ADC является средством процессорадля сложения длинных двоичных чисел, размерность которых превосходит поддерживаемые процессором размеры стандартных полей.Рассмотрим пример вычисления суммы чисел (листинг 8.3).Листинг 8.3. Вычисление суммы чисел<1> ;prg_8_3.asm<2> masm<3> model<4> stack<5> .data<6> a db<7> .code<8> main:<9>mov<10>small256254;сегмент кодаax,@datamov ds.axxor ax,axadd al,17add al, ajnc ml;если нет переноса, то перейти на mladc ah,0;в ах сумма с учетом переноса<17> ml: ;...<18>exit:<19>mov ax,4c00h;стандартный выход<20>int 21h<21>end main;конец программыВ строках 13-14 создана ситуация, когда результат сложения выходит за границы операнда.
Эта возможность учитывается строкой 15, где команда JNC (хотяможно было обойтись и без нее) проверяет состояние флага CF. Если он установлен в 1, то результат операции получился большим по размеру, чем операнд, и дляего корректировки необходимо выполнить некоторые действия. В данном случаемы просто полагаем, что границы операнда расширяются до размера АХ, для чего172Глава 8.
Арифметические командыучитываем перенос в старший разряд командой ADC (строка 16). Напомню, что исследовать работу команд сложения без учета знака вы можете в отладчике. Дляэтого введите в текстовом редакторе текст листинга 8.3, получите исполняемый модуль, запустите отладчик и откройте в нем окна командами View > Dumpи View > Registers. Далее, в пошаговом режиме отладки можно более наглядно проследить за всеми процессами, происходящими в процессоре во время работы программы.Сложение двоичных чисел со знакомТеперь настала пора раскрыть небольшой секрет. Дело в том, что на самом делепроцессор не подозревает о различии между числами со знаком и числами без знака.
Вместо этого у него есть средства фиксации возникновения характерных ситуаций, складывающихся в процессе вычислений. Некоторые из них мы рассмотрелиранее при обсуждении команд сложения чисел без знака — это учет флага переноса CF. Установка этого флага в 1 говорит о том, что произошел выход за пределыразрядности операндов. Далее с помощью команды ADC можно учесть возможностьтакого выхода (переноса из младшего разряда) во время работы программы.Другое средство фиксации характерных ситуаций в процессе арифметическихвычислений — регистрация состояния старшего (знакового) разряда операнда, которое осуществляется с помощью флага переполнения OF в регистре EFLAGS(бит И).В главе 4 мы рассматривали, как представляются числа в компьютере.
При этомотмечали, что положительные числа представляются в двоичном коде, а отрицательные — в дополнительном. Рассмотрим различные варианты сложения чисел.Примеры призваны показать поведение двух старших битов операндов и правильность результата операции сложения.Первый вариант сложения чисел:30566 = 0111011101100110+00687 = 000000101010111131253 = 0111101000010101.Следим за переносами из 14-го и 15-го разрядов и за правильностью результата: переносов нет, результат правильный.Второй вариант сложения чисел:30566 = 0111011101100110+30566 = 011101110110011061132 = 1110111011001100.Произошел перенос из 14-го разряда; из 15-го разряда переноса нет.
Результатнеправильный, так как имеется переполнение — значение числа получилось больше, чем то, которое может иметь 16-разрядное число со знаком (+32 767).Третий вариант сложения чисел:Арифметические операции над целыми двоичными числами173-30566 = 10001000 10011010+-04875 = 1110110011110101-35441 = 0111010110001111.Произошел перенос из 15-го разряда, из 14-го разряда нет переноса. Результатнеправильный, так как вместо отрицательного числа получилось положительное(в старшем бите находится 0).Четвертый вариант сложения чисел:-4875 = 1110110011110101+-4875=1110110011110101-9750 = 1101100111101010.Есть переносы из 14-го и 15-го разрядов.
Результат правильный.Таким образом, мы исследовали все случаи и выяснили, что ситуация переполнения (установка флага OF в 1) происходит при переносе:* из 14-го разряда (для положительных чисел со знаком);в из 15-го разряда (для отрицательных чисел).И, наоборот, переполнения не происходит (то есть флаг OF сбрасывается в 0),если есть перенос из обоих разрядов или перенос отсутствует в обоих разрядах.Таким образом, ситуация переполнение регистрируется процессором с помощью флага переполнения OF. Дополнительно к флагу OF при переносе из старшегоразряда устанавливается в 1 и флаг переноса CF. Так как процессор не знает о существовании чисел со знаком и без знака, то вся ответственность за правильностьдействий с получившимися числами ложится на программиста. Теперь, наверное,понятно, почему мы столько внимания уделили тонкостям сложения чисел со знаком.
Учтя все это, мы сможем организовать правильный процесс сложения чисел —будем анализировать флаги CF и OF и принимать правильное решение! Проанализировать флаги CF и OF можно командами условного переходаJC\3MС и 30\JNO соответственно (глава 10).Что же касается команд сложения чисел со знаком, то из изложенного ранеепонятно, что в архитектуре IA-32 сами команды сложения чисел со знаком те же,что и для чисел без знака.Вычитание двоичных чисел без знакаАналогично анализу операции сложения, порассуждаем над сутью процессов, происходящих при выполнении вычитания.ш Если уменьшаемое больше вычитаемого, то проблем нет, — разность положительна, результат верен.ш Если уменьшаемое меньше вычитаемого, возникает проблема: результат меньше 0, а это уже число со знаком.