Семинары по курсу «Архитектура ЭВМ и язык ассемблера» учебно-методическое пособие. Часть 1. - Е.А. Кузьменкова_ В.С. Махнычев_ В.А. Падарян (1110587), страница 5
Текст из файла (страница 5)
нулями для неотрицательногочисла и единицами для отрицательного числа).movmovzxmovsxmovsxbx,ebx,eax,ecx,0xA67Bbxbxbl;;;;bxebxeaxecx←←←←0xA67B0x0000A67B0xFFFFA67B0x0000007BПример 2-1 Интерпретация арифметических инструкцийВыпишите значение регистра AL в виде десятичного числа (знакового ибеззнакового), а также флаги CF, OF, ZF и SF после выполнения следующихинструкций.MOV AL, 70SUB AL, 130РешениеALзнаковое = -60, ALбеззнаковое = 196, CF = 1, OF = 1, ZF = 0, SF = 1.Для наглядности формирования значений флагов промоделируем выполнениезаданного фрагмента кода над шестнадцатеричным представлением данных.70 = 46h,130 = 82h46h – 82h = C4h, при этом по правилам формирования флага CF (CarryFlag) этот флаг получит значение 1, поскольку первый операнд меньше второго.Результат выполнения операции (C4h) отличен от 0, следовательно, флаг ZF (ZeroFlag) получит значение 0.
Во флаге SF (Sign Flag) фиксируется значение знаковогобита результата, т.е. его старшего бита. В нашем случае это 1, следовательно, флагSF получит значение 1.Проинтерпретируем полученный результат как десятичное число без знака и числосо знаком:C4h = 196 – это значение результата, интерпретируемое как десятичноечисло без знака. Это же значение представляет собой дополнительный кодотрицательного числа -60 (196 = 256 – 60 = доп(-60)), поэтому результатвыполнения операции, интерпретируемый как десятичное число со знаком, равен-60.Для определения значения флага OF (Overflow Flag) промоделируем операциювычитания над знаковыми десятичными числами. Заметим, что второй операнд(число 130) представляет собой дополнительный код отрицательного числа -12626(130 = доп(-126)). Следовательно, для знаковых чисел указанное вычитаниеприобретает вид:70 – (-126) = 196Полученный результат (196) не принадлежит допустимому диапазону значенийзнаковых чисел в формате байта [-128, 127], следовательно, флаг OF получитзначение 1.Пример 2-2 Объявление переменнойТребуется написать ассемблерную программу, в которой:1.
Выделяется память согласно следующему объявлениюstatic int var;2. Выделенная память используется для ввода десятичного числа, …3. у которого знак меняется на противоположный, …4. а само число после этого печатается в шестнадцатеричном формате.РешениеДля размещения переменной var используем сегмент статическихнеинициализированных данных .bss. Поскольку размер типа int в архитектуреIA-32 составляет четыре байта, используем директиву var resd 1. Выделеннаяпамять показана на рисунке ниже.С точки зрения языка Си переменная var – содержимое четырех байт памяти, но вязыке ассемблера символьное имя var будет интерпретироваться как адрес,причем адрес первого байта из четырех, выделенных для хранения некоторыхпроизвольных данных. Этот адрес, т.е. его символьное обозначение будетиспользоваться при обращении к памяти.27%include 'io.inc'section .bssvar resd 1section .textglobal CMAINCMAIN:GET_DEC 4, [var];;NEG DWORD [var];MOV EAX, DWORD [var] ;;PRINT_HEX 4, EAX;NEWLINE;MOV EAX, 0RETВводим десятичное число непосредственнов выделенные 4 байта памятиМеняем у числа знак на противоположныйЗагружаем значение переменной var на регистр,используя ее имя как адресПечатаем число в шестнадцатеричном форматеНе забываем затем перейти на новую строкуПример 2-3 Приведение типаЗаписать эквивалентную данному фрагменту на языке Си программу на языкеассемблера.static short int a = 10;static int b = 20, с;c = a + b;РешениеПеременные a и b инициализированы при объявлении – размещаем их в секции.data.
Переменная c помещается в секции неинициализированных статическихданных .bss.section .dataa dw 10b dd 20section .bssc resd 1section .textmovsx eax, word [a] ; Знаковое расширение данныхaddeax, dword [b] ;movdword [c],eax ;В вычислении суммы участвуют переменные с разными типами. Прежде чем будетвыполнено сложение, типы операндов должны быть приведены к одному общему28типу. В данном случае значение переменной a должно быть расширено до типаint.Пример 2-4 Приведение беззнакового типаЗаписать эквивалентную данному фрагменту на языке Си программу на языкеассемблера.unsigned char z = 0xff;unsigned short a = 0xff00;unsigned int b;b = a * z;РешениеПоскольку выполняется арифметическая операция, происходит integer promotions,неявное приведение операндов к целому типу стандартного размера.
Результатоперации в данном примере может быть выражен знаковым целым типомстандартного размера:INT_MIN < 0 < USHRT_MAX × UCHAR_MAX < INT_MAXДля 32-разрядной архитектуры IA-32 и компилятора gcc, величины, входящие внеравенство имеют следующие значения.Таблица 4. Предельные значения некоторых типов данных языка Си.КонстантаОписаниеINT_MINМинимальное значение стандартного целого типаUSHRT_MAX Максимальное значение беззнакового короткогоцелого типаUCHAR_MAX Максимальное значение беззнакового целого типаcharINT_MAXМаксимальное значение стандартного целого типаВеличина-2147483648655352552147483647Объявлены эти константы в стандартном заголовочном файле limits.h.Таким образом, выполнение умножения потребует сначала расширить обаоперанда до стандартного целого типа, потом выполнить операцию знаковогоумножения и сохранить результат в переменной b.
Причем, последнее присвоениене будет производить никаких преобразований над полученным при умножениичислом.29section .bssb resd 1section .dataz db 0xffa dw 0xff00section .textmovzx eax, byte [z] ;;movzx edx, word [a] ;;imul eax, edx;mov dword [b], eax ;выполняем беззнаковое расширениеиз 8 разрядов в 32выполняем беззнаковое расширениеиз 16 разрядов в 32умножаемсохраняем полученное значениеПример 2-5 УмножениеЗаписать эквивалентную данному фрагменту на языке Си программу на языкеассемблера.
Описать секции кода, инициализированных и неинициализированныхданных.static int a, b = 1, c = -2, d = 3;...a = b + c * d;РешениеПеременная a не имеет инициализирующего значения и будет размещена всекции .bss. Остальные переменные помещаются в секции .data.section .bssa resd 1section .datab dd 1c dd -2d dd 3В первую очередь вычисляется произведение переменных c и d. Используетсяформа инструкции IMUL с одним операндом, второй операнд задан неявно, эторегистр EAX. Результат будет сохранен в паре регистров EDX:EAX.
Старшие разрядырезультата, т.е. содержимое регистра EDX, в дальнейших вычислениях неиспользуются, поскольку в языке Си тип результата умножения совпадет с типамиоперандов-выражений (необходимо не забывать о неявном приведении типов30операндов).
После сложения полученный результат выгружается обратно изрегистра EAX в память.sectionmovimuladdmov.texteax, dword [c]dword [d]eax, dword [b]dword [a], eaxПример 2-6 ДелениеЗаписать эквивалентную данному фрагменту на языке Си программу на языкеассемблера.static int x, y;...x /= -y;РешениеПоскольку x и y объявлены как статические переменные, размещаем их в секциинеинициализированных статических данных.section .bssx resd 1y resd 1Реализация выражения, в котором происходит деление, состоит из загрузкизначений переменных x и y на регистры, обращения знака, деления и выгрузкиполученного результата обратно в память.31section .textmov eax, dword [х] ;;;;;;;;;mov edx, eax;sar edx, 31;;;;;mov ecx, dword [y] ;;neg ecx;;idiv ecx;mov dword [x], eax ;;Записываем в регистр eax значениепеременной x. Поскольку в дальнейшемэто значение будет выступать вкачестве делимого, его необходиморазместить в паре регистров edx:eaxТаким образом, 32-разрядное знаковоечисло будет расширено до 64 разрядов.верхние 32 разряда заполнятся знаковымбитом.Копируем значение переменной x в edxСдвигаем число на 31 разряд – всеразряды регистра будут заполненызнаковым битом, т.к.
сдвигарифметический, пара регистров edx:eaxготова к знаковому делению.Записываем в регистр ecx значениепеременной yМеняем знак числа, т.е. получаемзначение (–y)делимчастное из регистра eax записываем впамять, где размещена переменная xПример 2-7 Арифметика «длинных» чиселПо заданному фрагменту на языке Си написать эквивалентный код на языкеассемблера.static long long x;…x++;РешениеПеременная x будет размещена в секции неинициализированных статическихданных в формате учетверенного слова:section .bssx resq 1Поскольку максимальный допустимый размер операнда в арифметическихкомандах – двойное слово (32 бита), для реализации арифметики над 64разрядными числами их разбивают на две части по 32 бита каждая и выполняютсоответствующие операции над этими частями.
В нашем случае необходимо32увеличить младшую часть x на 1 и учесть возникающий при этом возможныйперенос из старшего разряда. Возникающий при сложении младших частейперенос фиксируется во флаге CF, поэтому дальнейшее сложение старших частейнадо выполнять с учетом данного флага, для чего следует использовать командуADC. Принимая во внимание «перевернутое» представление в памяти чиселразмером больше байта, получаем следующий код:section .textadd dword[x], 1; Сложение младших частейadc dword[x + 4], 0 ; Учитываем возможный перенос из; старшего разрядаЗаметим, что реализовывать в данном примере увеличение младшей части x на 1командой INC нельзя, т.к.