assembler. Учебник для вузов_Юров В.И_2003 -637с (862834), страница 41
Текст из файла (страница 41)
Команда в строке 18 формирует младшую частьрезультата. Теперь обратите внимание на сегмент данных, а именно на строку 6.В этой строке содержится директива label. Мы еще не раз будем сталкиваться с этойдирективой. В данном случае она назначает еще одно символическое имя rez адресу, на который уже указывает другой идентификатор rez_l. Различие заключаетсяв типах этих идентификаторов — rez имеет тип слова, который ему назначаетсядирективой label (имя типа указано в качестве операнда label). Введя эту директиву в программе, мы подготовились к тому, что, возможно, результат операцииАрифметические операции над целыми двоичными числами179умножения будет занимать в памяти целое слово.
Обратите внимание на то, чтомы не нарушили принципа: младший байт по младшему адресу. Далее, используяимя rez, можно обращаться к значению в этой области как к слову.В заключение можно исследовать в отладчике программу на разных наборахсомножителей.Умножение двоичных чисел со знакомДля умножения чисел со знаком предназначена командаimul. о п е р а н д _ 1 [ , о п е р а н д _ 2 , о п е р а н д _ 3 ]Эта команда выполняется так же, как и команда MUL. Отличительной особенностью команды IMUL является только формирование знака. Если результат мали умещается в одном регистре (то есть если CF= OF= 0), то содержимое другогорегистра (старшей части) является расширением знака — все его биты равны старшему биту (знаковому разряду) младшей части результата.
В противном случае(если CF = OF = 1) знаком результата является знаковый бит старшей части результата, а знаковый бит младшей части является значащим битом двоичного кода результата. Если вы найдете в приложении команду IMUL, то увидите, что у нее имеются более широкие возможности по заданию местоположения операндов. Этосделано для удобства использования.Деление двоичных чисел без знакаДля деления чисел без знака предназначена командаd i v делительДелитель может находиться в памяти или в регистре и иметь размер 8, 16 или32 бита.
Местонахождение делимого фиксировано и так же, как в команде умножения, зависит от размера операндов. Результатом команды деления являются значения частного и остатка. Варианты местоположения и размеров операндов операции деления показаны в табл. 8.3.Таблица 8.3. Расположение операндов и результата при деленииДелимоеСлово (16 бит)в регистре АХДелительБайт в регистре илив ячейке памятиЧастноеБайт в регистреALОстатокБайт врегистре АНДвойное слово (32 бита),в DX — старшая часть,в АХ — младшая частьСлово (16 бит) в регистре или в ячейкепамятиСлово (16 бит) врегистре АХСлово (16 бит)в регистре DXДвойное слово(32 бита) врегистре ЕАХДвойное слово(32 бита) врегистре EDXДвойное словоУчетверенное слово(64 бит), в EDX — старшая (32 бита) в регистреили в ячейке памятичасть, в ЕАХ — младшаячастьПосле выполнения команды деления содержимое флагов неопределенно, новозможно возникновение прерывания с номером 0, называемого «деление на ноль».Этот вид прерывания относится к так называемым исключениям и возникает внутри процессора из-за некоторых аномалий в вычислительном процессе.
К вопросу1 80Глава 8. Арифметические командыоб исключениях мы еще вернемся. Прерывание 0 (деление на ноль) при выполнении команды DIV может возникнуть по одной из следующих причин:ш делитель равен нулю;* частное не входит в отведенную под него разрядную сетку, что может случиться:П при делении делимого величиной в слово на делитель величиной в байт,причем значение делимого более чем в 256 раз больше значения делителя;П при делении делимого величиной в двойное слово на делитель величинойв слово, причем значение делимого более чем в 65 536 раз больше значенияделителя;П при делении делимого величиной в учетверенное слово на делитель величиной в двойное слово, причем значение делимого более чем в 4 294 967 296раз больше значения делителя.К примеру, выполним деление значения в области del на значение в областиdelt (листинг 8.6).Листинг 8.6.
Деление чисел<1> ;prg_8.6.asm<2> masm<3> modelsmall<4> stack256<5> .data<6> del_blabel<7> del dw 29876<8> deltdb 45<9> .code<10>main:<12><13><14><15><16>byte;сегмент кода;точка входа в программухог а х , ахпоследующие две команды можно заменить одной mov a x , delmov ah,del_bmov al,del_b+ldiv deltстарший байт делимого в ahмладший байт делимого в alв al - частное, в ah - остатокконец программы<18>end mainВыполнение программы в таком виде приведет к ошибке деления на ноль.
Причина описана ранее — частное не входит в отведенную под него разрядную сетку.Это происходит в случаях, когда делимое больше делителя на определенную величину. А что же делать, если соотношение делимое и делителя именно такое? Подробно деление, как, впрочем, и умножение, целых чисел произвольной разрядности описано в книге [8]. Чтобы исправить пример из листинга 8.6, необходимоизменить разрядность делимого, исходя из разрядности делителя и требований команды DIV. К примеру, делимое можно сделать равным 298.
Пример будет выполнен без ошибок.Деление двоичных чисел со знакомДля деления чисел со знаком предназначена командаi d i v делительДля этой команды справедливы все рассмотренные ранее рассуждения, касающиеся команд и чисел со знаком. Отметим лишь особенности возникновения ис-Вспомогательные команды для арифметических вычислений181ключения 0 (деление на ноль) в случае чисел со знаком. Оно возникает при выполнении команды IDIV по одной из следующих причин:Я делитель равен нулю;и частное не входит в отведенную для него разрядную сетку, что, в свою очередь,может произойти:П при делении делимого величиной в слово со знаком на делитель величинойв байт со знаком, причем значение делимого более чем в 128 раз больше значения делителя (таким образом, частное не должно находиться вне диапазона от-128 до+127);D при делении делимого величиной в двойное слово со знаком на делительвеличиной в слово со знаком, причем значение делимого более чем в 32 768раз больше значения делителя (таким образом, частное не должно находитьсявне диапазона от -32 768 до +32 768);П при делении делимого величиной в учетверенное слово со знаком на делитель величиной в двойное слово со знаком, причем значение делимого болеечем в 2 147 483 648 раз больше значения делителя (таким образом, частноене должно находиться вне диапазона от -2 147 483 648 до +2 147 483 647).Вспомогательные командыдля арифметических вычисленийВ системе команд процессора есть несколько команд, которые облегчают программирование алгоритмов, производящих арифметические вычисления, а также помогают разрешать проблемы, возникающие при подобных вычислениях.Команды преобразования типовЧто делать, если размеры операндов, участвующих в арифметических операциях,разные? Например, предположим, что в операции сложения один операнд занимает слово, а другой — двойное слово.
Ранее было сказано, что в операции сложениядолжны участвовать операнды одного формата. Если числа без знака, то выходнайти просто. В этом случае можно на базе исходного операнда сформировать новый операнд (формата двойного слова), старшие разряды которого просто заполнить нулями.
Сложнее ситуация для чисел со знаком: как динамически, в ходе выполнения программы, учесть знак операнда? Для решения подобных проблемв системе команд процессора есть так называемые команды преобразования типа.Эти команды расширяют байты в слова, слова — в двойные слова и двойные слова—в учетверенные слова (64-разрядные значения). Команды преобразования типаособенно полезны при преобразовании целых со знаком, так как они автоматически заполняют старшие биты вновь формируемого операнда значениями знакового бита исходного объекта. Эта операция приводит к целым значениям того жезнака и той же величины, что и исходная, но уже в более длинном формате.
Подобное преобразование называется операцией распространения знака.Существуют два вида команд преобразования типа.182Глава 8. Арифметические командыII Команды без операндов — эти команды работают с фиксированными регистрами:П CBW (Convert Byte to Word) — команда преобразования байта (в регистреAL) в слово (в регистре АХ) путем распространения значения старшего битаAL на все биты регистра АН;П CWD (Convert Word to Double) — команда преобразования слова (в регистреАХ) в двойное слово (в регистрах DX:AX) путем распространения значениястаршего бита ах на все биты регистра DX;О CWDE (Convert Word to Double) — команда преобразования слова (в регистре АХ) в двойное слово (в регистре ЕАХ) путем распространения значениястаршего бита АХ на все биты старшей половины регистра ЕАХ;D CDQ (Convert Double Word to Quarter Word) — команда преобразования двойного слова (в регистре ЕАХ) в учетверенное слово (в регистрах EDX:EAX) путем распространения значения старшего бита ЕАХ на все биты регистра EDX;it Команды обработки строк (также глава 12).
Эти команды обладают полезнымсвойством в контексте нашей проблемы:П movsx операнд_1,операнд_2 — команда пересылки с распространением знакарасширяет 8- или 16-разрядное значение операнд_2, которое может быть регистром или операндом в памяти, до 16- или 32-разрядного значения в одном из регистров, используя знаковый бит для заполнения старших позицийзначения операнд_1 (данную команду удобно использовать для подготовкиоперандов со знаками к выполнению арифметических операций);П movzx операнд_1,операнд_2 — команда пересылки с расширением нулем расширяет 8- или 16-разрядное значение операнд_2 до 16- или 32-разрядногос очисткой (заполнением) нулями старших позиций значения операнд_2(данную команду удобно использовать для подготовки операндов без знакак выполнению арифметических действий).К примеру, вычислим значение у = (а + Ь)/с, где а, Ь, с — байтовые знаковыепеременные (листинг 8.7).Листинг 8.7.