- •Содержание
- •Введение
- •ДЕНЬ 1
- •Знакомство с архитектурой компьютера
- •1.1. Что такое архитектура компьютера
- •1.2. Системы счисления
- •1.3. Биты и байты
- •1.4. Фон-неймановская архитектура
- •1.5. Процессор
- •1.5.1. Режимы работы процессора
- •1.5.2. Регистры процессора
- •1.5.2.1. Пользовательские регистры
- •1.5.2.1.1. Регистры общего назначения
- •1.5.2.1.2. Сегментные регистры
- •1.5.2.1.3. Регистр флагов и указателя команд
- •1.5.2.2.Системные регистры
- •1.5.2.3. Регистры FPU и MMX
- •1.5.2.4. Регистры XMM (расширение SSE/SSE2)
- •1.6. Память
- •1.8. Шины
- •ДЕНЬ 2
- •Основы программирования на ассемблере
- •2.1. Какой ассемблер выбрать
- •2.2. Этапы создания программы
- •2.3. Структура программы
- •2.3.1. Метка
- •2.3.2. Команда или директива
- •2.3.3. Операнды
- •2.3.4. Комментарий
- •2.4. Некоторые важные директивы ассемблера
- •2.4.1. Директивы определения данных
- •2.4.2. Директива эквивалентности
- •2.4.3. Директива присваивания
- •2.4.4. Директивы задания набора допустимых команд
- •2.4.5. Упрощенные директивы определения сегмента
- •2.4.6. Директива указания модели памяти
- •2.5. Разработка нашей первой программы на ассемблере
- •2.5.1. Программа типа COM
- •2.5.2. Программа типа EXE
- •2.6. Основные различия между программами типа EXE и COM
- •2.7. Функции BIOS и DOS
- •2.8. Префикс программного сегмента (PSP)
- •2.9. Знакомство с отладчиком
- •2.10. Младший байт по младшему адресу
- •ДЕНЬ 3
- •Основные конструкции ассемблера
- •3.1. Цикл
- •3.2. Безусловный переход
- •3.3. Сравнение и условные переходы
- •3.4. Стек
- •3.5. Подпрограммы (процедуры)
- •3.6. Директива INCLUDE
- •3.7. Конструкции времени исполнения программы
- •3.8. Директивы условного ассемблирования
- •3.9. Макросы
- •3.9.1. Блоки повторений
- •ДЕНЬ 4
- •Основные команды ассемблера
- •4.1. Команды пересылки
- •4.2. Оператор PTR
- •4.3. Способы адресации
- •4.3.1. Непосредственная адресация
- •4.3.2. Регистровая адресация
- •4.3.3. Косвенная адресация
- •4.3.4. Прямая адресация (адресация по смещению)
- •4.3.5. Базовая адресация
- •4.3.6. Индексная адресация
- •4.3.7. Базовая-индексная адресация
- •4.3.8. Адресация по базе с индексированием и масштабированием
- •4.4. Относительные операторы
- •4.5. Логические команды
- •4.6. Команды сдвига
- •4.6.1. Команды линейного (нециклического) сдвига
- •4.6.2. Команды циклического сдвига
- •4.7. Команды обработки строк/цепочечные команды
- •4.7.1. Команды пересылки цепочек
- •4.7.2. Команды сравнения цепочек
- •4.7.3. Команды сканирования цепочек
- •4.7.4. Команды загрузки элемента из цепочки в аккумулятор
- •4.7.6. Команды ввода элемента цепочки из порта ввода-вывода
- •4.7.7. Команды вывода элемента цепочки в порт ввода-вывода
- •4.8. Команды работы с адресами и указателями
- •4.9. Команды трансляции (преобразования) по таблице
- •ДЕНЬ 5
- •Арифметические команды. Сопроцессор
- •5.1. Арифметические операторы
- •5.2. Команды выполнения целочисленных операций
- •5.2.1. Целые двоичные числа
- •5.2.2. BCD-числа
- •5.2.3. Команды, работающие с целыми двоичными числами
- •5.2.3.1. Сложение и вычитание
- •5.2.3.2. Инкремент и декремент
- •5.2.3.3. Умножение и деление
- •5.2.3.4. Изменение знака числа
- •5.2.4. Ввод и вывод чисел
- •5.2.5.1. Сложение и вычитание неупакованных BCD-чисел
- •5.2.5.2. Умножение и деление неупакованных BCD-чисел
- •5.2.5.3. Сложение и вычитание упакованных BCD-чисел
- •5.3. Команды выполнения операций с вещественными числами
- •5.3.1. Вычисления с фиксированной запятой
- •5.3.2. Вычисления с плавающей запятой
- •5.3.2.1. Сравнение вещественных чисел
- •5.4. Архитектура сопроцессора
- •5.4.1. Типы данных FPU
- •5.4.2. Регистры FPU
- •5.4.2.1. Регистры данных R0-R7
- •5.4.2.2. Регистр состояния SWR (Status Word Register)
- •5.4.2.3. Регистр управления CWR (Control Word Register)
- •5.4.2.4. Регистр тегов TWR (Tags Word Register)
- •5.4.2.5. Регистры-указатели команд IPR (Instruction Point Register) и данных DPR (Data Point Register)
- •5.4.3. Исключения FPU
- •5.4.4. Команды сопроцессора
- •5.4.4.1. Команды пересылки данных FPU
- •5.4.4.2. Арифметические команды
- •5.4.4.3. Команды манипуляций константами
- •5.4.4.4. Команды управления сопроцессором
- •5.4.4.5. Команды сравнения
- •5.4.4.6. Трансцендентные команды
- •ДЕНЬ 6
- •Программирование под MS-DOS
- •6.2. Вывод на экран в текстовом режиме
- •6.2.1. Функции DOS
- •02h (INT 21h) — вывод символа с проверкой на <Ctrl>+<Break>
- •06h (INT 21h) — вывод символа без проверки на <Ctrl>+<Break>
- •09h (INT 21h) — вывод строки на экран с проверкой на <Ctrl>+<Break>
- •40h (INT 21h) — записать в файл или на устройство
- •INT 29h — быстрый вывод символа на экран
- •6.2.2. Прямая запись в видеопамять
- •6.3. Ввод с клавиатуры
- •6.3.1. Функции DOS
- •01h (INT 21h) — ввод символа с эхо
- •06h (INT 21h) — ввод-вывод через консоль
- •07h (INT 21h) — нефильтрованный ввод без эхо
- •08h (INT 21h) — ввод символа без эхо
- •0Ah (INT 21h) — буферизированный ввод с клавиатуры
- •0Bh (INT 21h) — проверить состояние ввода
- •0Ch (INT 21h) — очистить буфер и считать символ
- •3Fh (INT 21h) — чтение из файла или устройства
- •6.3.2. Функции BIOS
- •00h, 10h, 20h (INT 16h) — прочитать символ с клавиатуры с ожиданием
- •01h, 11h, 21h (INT 16h) — проверка символа
- •02h, 12h, 22h (INT 16h) — считать состояние клавиатуры
- •6.4. Работа с файлами
- •6.4.1. Создание и открытие файлов
- •3Ch (INT 21h) — создать файл
- •3Dh (INT 21h) — открыть существующий файл
- •5Bh (INT 21h) — создать и открыть существующий файл
- •5Ah (INT 21h) — создать и открыть временный файл
- •6Ch (INT 21h) — создать или открыть файл с длинным именем
- •6.4.2. Чтение и запись в файл
- •3Fh (INT 21h) — чтение из файла или устройства
- •42h (INT 21h) — установить указатель чтения/записи
- •40h (INT 21h) — записать в файл или на устройство
- •68h (INT 21h) — сброс файловых буферов MS-DOS на диск
- •0Dh (INT 21h) — сброс всех файловых буферов на диск
- •6.4.3. Закрытие и удаление файла
- •3Eh (INT 21h) — закрыть файл
- •41h (INT 21h) — удалить файл
- •LFN 41h (INT 21h) — удалить файл c длинным именем
- •6.4.4. Поиск файлов
- •4Eh (INT 21h) — найти первый файл
- •4Fh (INT 21h) — найти следующий файл
- •LFN 4Eh (INT 21h) — найти первый файл с длинным именем
- •LFN 4Fh (INT 21h) — найти следующий файл
- •LFN A1h (INT 21h) — закончить поиск файла
- •6.4.5. Управление директориями
- •39h (INT 21h) — создать директорию
- •LFN 39h (INT 21h) — создать директорию с длинным именем
- •3Ah (INT 21h) — удалить директорию
- •LFN 3Ah (INT 21h) — удалить директорию с длинным именем
- •47h (INT 21h) — определить текущую директорию
- •LFN 47h (INT 21h) — определить текущую директорию с длинным именем
- •3Bh (INT 21h) — сменить директорию
- •LFN 3Bh (INT 21h) — сменить директорию с длинным именем
- •6.5. Прерывания
- •6.5.1. Внутренние и внешние аппаратные прерывания
- •6.5.2. Запрет всех маскируемых прерываний
- •6.5.3. Запрет определенного маскируемого прерывания
- •6.5.4. Собственный обработчик прерывания
- •Функция 35h (INT 21h) — получить вектор прерываний
- •Функция 25h (INT 21h) — установить вектор прерываний
- •6.5.5. Распределение номеров прерываний
- •ДЕНЬ 7
- •7.2. Первая простейшая программа под Windows на ассемблере
- •7.2.1. Директива INVOKE
- •7.3. Консольное приложение
- •7.4. Графическое приложение
- •7.4.1. Регистрация класса окон
- •7.4.2. Создание окна
- •7.4.3. Цикл обработки очереди сообщений
- •7.4.4. Процедура главного окна
- •7.5. Дочерние окна управления
- •7.6. Использование ресурсов
- •7.6.1. Подключение ресурсов к исполняемому файлу
- •7.6.2. Язык описания ресурсов
- •7.6.2.1. Пиктограммы
- •7.6.2.2. Курсоры
- •7.6.2.3. Растровые изображения
- •7.6.2.4. Строки
- •7.6.2.5. Диалоговые окна
- •7.6.2.6. Меню
- •7.7. Динамические библиотеки
- •7.7.1. Простейшая динамическая библиотека
- •7.7.2. Неявная загрузка DLL
- •7.7.3. Явная загрузка DLL
- •Приложение 1. Основные технические характеристики микропроцессоров фирмы Intel
- •Приложение 2. Таблицы кодов символов
- •Приложение 3. Сравнение двух синтаксисов ассемблера
- •Список литературы
http://www.sklyaroff.ru |
79 |
соответствует умножению операнда на степени двойки, а вправо, соответственно, делению операнда на степени двойки. То есть сдвиг влево на один бит соответствует умножению операнда на 2, сдвиг влево на два бита соответствует умножению на 4, на три бита — умножению на 8 и т. д.
Аналогично с делением. Сдвиг вправо на один бит соответствует делению на 2, сдвиг вправо на два бита соответствует делению на 4, на три бита — делению на 8 и т. д. Можете проверить это самостоятельно.
Команды арифметического сдвига выполняют умножение и деление на степень двойки намного быстрее, чем команды MUL, DIV и IDIV, поэтому программисты на ассемблере и используют их.
4.6.2. Команды циклического сдвига
Команды из второй группы имеют следующий синтаксис:
ROL операнд,счетчик ; циклический сдвиг влево
ROR операнд,счетчик ; циклический сдвиг вправо
RCL операнд,счетчик ; циклический сдвиг влево через флаг переноса RCR операнд,счетчик ; циклический сдвиг вправо через флаг переноса
Команды циклического сдвига выполняют циклический сдвиг битов (ротацию) влево или вправо.
Команды ROL и ROR сдвигают все биты операнда соответственно влево или вправо на столько бит, сколько указано в счетчике, но в отличие от команд линейного (нециклического) сдвига не обнуляют освобожденные разряды, а снова вдвигают их с другой стороны, т. е. старшие биты попадают в младшие или наоборот.
Примеры:
mov al,C8h ; al= 11001000b ror al,4
; Теперь al = 10001100b. Флаг переноса cf=1, т. к. последний выдвинутый слева бит был 1.
mov bh,D6h ; bh= 11010110b rol bh,3
; Теперь bh = 10110110b. Флаг переноса cf=0, т. к. последний выдвинутый слева бит был 0.
Команды RCL и RCR выполняют действие аналогичное командам ROL и ROR, но включают флаг переноса CF в цикл, как если бы он был дополнительным битом в операнде. Последний выдвигаемый бит заносится в флаг CF, а значение CF при этом поступает в освободившуюся позицию Должно быть понятно, что команда RCL помещает значение CF в младший разряд, а команда RCR в старший.
Примеры:
mov al,C8h ; al= 11001000b rcr al,4
; Теперь al = 11000110b. В старший разряд был вдвинут флаг переноса cf=1, т. к. последний выдвинутый слева бит был 1.
mov bh,D6h ; bh= 11010110b rcl bh,3
; Теперь bh = 01101100b. В младший разряд был вдвинут флаг переноса cf=0, т. к. последний выдвинутый справа бит был 0.
4.7. Команды обработки строк/цепочечные команды
Команды обработки строк или цепочечные команды работают с последовательностями элементов. Один элемент может быть размером в байт (8 бит), слово (16 бит) или двойное слово (32 бита). Обычно последовательностями
http://www.sklyaroff.ru |
80 |
элементов являются обычные строки символов, поэтому эти команды и называют командами обработки строк. Во всех цепочечных командах строка-источник должна находиться стандартно по адресу DS:SI (или DS:ESI), то есть в сегменте данных, определяемом регистром DS со смещением SI (или ESI), а строка-приемник по адресу в ES:DI (или ES:EDI) иначе говоря в сегменте данных, адресуемом сегментным регистром ES.
Все цепочечные команды за один раз обрабатывают только один элемент цепочки (строки). Для того чтобы команда выполнялась над всей строкой, используется один из префиксов повторения операций:
REP — повторять;
REPE — повторять, пока равно;
REPZ — повторять, пока ноль; REPNE — повторять, пока не равно; REPNZ — повторять, пока не ноль.
Эти префиксы указываются перед нужной цепочечной командой в поле метки и заставляют команду выполняться в цикле. Без префикса цепочечная команда выполняется один раз. Все префиксы анализируют значение регистра ECX/CX, а также флаг нуля ZF (кроме префикса REP).
Префикс повторения REP (от англ. REPeat — повторять) обычно используется совместно с командами MOVS и STOS и заставляет данные команды выполняться, пока содержимое в регистрах ECX/CX не станет равным 0. При этом цепочечная команда, перед которой стоит префикс, автоматически уменьшает содержимое ECX/CX на единицу. Та же команда, но без префикса этого не делает.
Префиксы повторения REPE (REPeat while Equal — повторять пока равно) и REPZ (REPeat while Zero — повторять пока ноль) являются абсолютно идентичными и обычно применяются с командами CMPS и SCAS для поиска отличающихся элементов цепочек. Эти префиксы заставляют цепочечные команды циклически выполняться, пока содержимое ECX/CX не равно нулю или пока флаг ZF не будет сброшен в 0, если это произойдет, управление будет передано следующей команде программы.
Префиксы повторения REPNE (REPeat while Not Equal — повторять пока не равно) или REPNZ (REPeat while Not Zero — повторять пока не ноль) также являются абсолютно идентичными и используются обычно с командами CMPS и SCAS, но для поиска совпадающих элементов. Эти префиксы заставляют цепочечные команды циклически выполняться до тех пор, пока содержимое ECX/CX не равно нулю или пока флаг ZF не будет установлен в 1, если это произойдет, управление будет передано следующей команде программы.
Строки в командах обработки строк могут обрабатываться либо от начала к концу, либо, наоборот, от конца к началу. Направление обработки задает флаг направления DF. Флаг направления анализируют цепочечные команды и если DF=0, то обрабатывают элементы в направлении возрастания адресов, если DF=1, то в направлении убывания адресов. Состоянием флага DF можно управлять с помощью команд CLD и STD, не имеющих операндов
CLD (Clear Dierction Flag) — сбрасывает флаг направления DF в 0, в результате чего при последующих строковых операциях значение в регистрах DI и SI будет увеличиваться.
STD (Set Direction Flag) — устанавливает флаг направления DF в 1, в результате чего при последующих строковых операциях значение в регистрах DI и SI будет уменьшаться.
Обратите внимание, что в каждой группе цепочечных команд (ниже) имеется одна команда с двумя операндами и несколько команд без операндов. На самом деле в процессоре существуют только цепочечные команды без операндов. При использовании команды с операндами транслятор ассемблера сам определяет по типу указанных операндов, какую из трех форм команды без операндов сгенерировать.
4.7.1. Команды пересылки цепочек
В эту группу входят следующие команды:
http://www.sklyaroff.ru |
81 |
movs приемник,источник (MOVe String) — переслать цепочку; movsb (MOVe String Byte) — переслать цепочку байт;
movsw (MOVe String Word) — переслать цепочку слов;
movsd (MOVe String Double word) — переслать цепочку двойных слов.
Команда MOVSB копирует байт из ячейки памяти, адресуемой парой регистров DS:SI (DS:ESI), в ячейку памяти, адресуемой парой регистров ES:DI (ES:EDI). Действие команды MOVSW аналогично, только копируется слово. Соответственно команда MOVSD копирует двойное слово. Команда MOVS с операндами транслируется в одну из трех команд без операндов: MOVSB, MOVSW, MOVSD.
Без префикса команда пересылки цепочек копирует только один элемент цепочки. С префиксом REP можно переслать до 64 Кбайт данных в 16-разрядной программе или до 4 Гбайт данных в 32-разрядной программе. Число пересылаемых элементов должно быть указано в регистре CX/ECX.
Алгоритм пересылки элементов цепочки может выглядеть так:
5.Загрузить адрес источника в регистр DS:SI (DS:ESI), а адрес приемника в ES:DI (ES:EDI).
6.Задать с помощью команды CLD или STD направление обработки цепочки (от начала к концу или от конца к началу).
7.Задать в регистре ECX/CX число обрабатываемых элементов.
8.Выдать команду MOVS (MOVSB, MOVSW или MOVSD) с префиксом REP. Например, следующий блок кода копирует 10 байт строки text1 в строку text2:
lea SI,text1 lea DI,text2 cld
mov CX,10 rep movsb
При этом предполагается, что строка text1 находится в сегменте данных, на который указывает регистр DS, а строка text2 — в сегменте, на который указывает регистр ES (для программы типа .COM значение регистров DS и ES совпадает).
4.7.2. Команды сравнения цепочек
В эту группу входят следующие команды:
cmps приемник,источник (CoMPare String) — сравнить строки; cmpsb (CoMPare String Word) — сравнить строку байт;
cmpsw (CoMPare String Word) — сравнить строку слов;
cmpsd (CoMPare String Double word) — сравнить строку двойных слов.
Команды этой группы сравнивают элементы цепочки-приемника (адресуемой регистрами ES:DI (ES:EDI)) с элементами цепочки-источника (адресуемой регистрами DS:SI (DS:ESI)). В зависимости от флага DF команда сравнения цепочек увеличивает или уменьшает адреса в регистрах SI и DI на один байт (CMPSB), слово
(CMPSW) или двойное слово (CMPSD).
Принцип работы команд сравнения цепочек аналогичен команде сравнения CMP. Они так же, как и CMP, производят вычитание элементов, не записывая при этом результата, и устанавливают флаги ZF, SF и OF.
Если использовать команду сравнения цепочек с префиксами повторения REPNE/REPNZ или REPE/REPZ, то сравниваться будут столько элементов, сколько указано в регистре CX/ECX. При этом в случае префиксов REPNE/REPNZ сравнение прекратится при первом совпадении в цепочке, а в случае префиксов REPE/REPZ – при первом несовпадении.
Для определения причины, которая привела к выходу из цикла сравнения цепочек, обычно используется команда условного перехода JCXZ. Эта команда анализирует содержимое регистра CX/ECX, и если оно равно нулю передает управление на метку, указанную в качестве операнда в JCXZ. Если значение в CX/ECX не равно нулю, то это означает, что выход произошел по причине совпадения или несовпадения очередных элементов в цепочке.
http://www.sklyaroff.ru |
82 |
В листинге 4.1 в качестве примера показана программа сравнения двух строк. Если строки text1 и text2 равны, то осуществляется переход на метку Equality.
Листинг 4.1. Программа сравнения двух строк (cmpstr.asm)
.model small
.stack 100h
.code
start:
mov |
ax,@data |
|
mov |
ds,ax |
|
mov |
es,ax |
|
lea |
si,text1 |
; в SI адрес начала строки text1 |
lea |
di,text2 |
; в DI адрес начала строки text2 |
cld |
|
|
; в CX длина строки text1 (число символов для сравнения) mov cx,len_text1
repe cmpsb |
; сравнивать, пока элементы равны |
||
je |
Equality |
|
|
mov |
dx,offset mes_no |
|
|
mov |
ah,9 |
|
|
int |
21h |
|
|
jmp |
exit |
|
|
Equality: |
|
|
|
mov |
dx,offset mes_yes |
|
|
mov |
ah,9 |
|
|
int |
21h |
|
|
exit: |
|
; выход из программы |
|
mov |
ax,4C00h |
|
|
int |
21h |
|
|
.data |
|
|
|
text1 |
db |
"Ivan Sklyaroff" |
; первая строка |
len_text1=$-text1 |
|
; длина первой строки |
|
text2 |
db |
"Ivan Sklyaroff" |
; вторая строка |
mes_yes |
db |
"Строки одинаковы",'$' |
|
mes_no |
db |
"Строки различны",'$' |
|
end start
4.7.3. Команды сканирования цепочек
В эту группу входят следующие команды:
scas приемник (SCAning String) — сканировать цепочку; scasb (SCAning String Byte) — сканировать цепочку байт; scasw (SCAning String Word) — сканировать цепочку слов;
scasd (SCAning String Double Word) — сканировать цепочку двойных слов.
http://www.sklyaroff.ru |
83 |
Команды сканирования цепочек осуществляют поиск заданного значения в строке. Значение, которое требуется найти, необходимо предварительно поместить в регистр AL (если ищется байт), в AX (если ищется слово) или в EAX (если осуществляется поиск двойного слова), а адрес строки должен быть сформирован в регистре ES:DI (ES:EDI). Принцип поиска тот же, что и в команде сравнения CMPS, то есть выполняется последовательное вычитание (из содержимого регистра аккумулятора содержимое очередного элемента цепочки) и в зависимости от результатов вычитания производится установка флагов, при этом ни один из операндов не изменяется.
Если использовать команду сканирования цепочки с префиксом REPE или REPZ, то команда будет выполняться в цикле до тех пор, пока не будет достигнут конец цепочки (содержимое CX/ECX равно 0) или пока не встретится элемент, отличный от элемента в регистре AL/AX/EAX.
Если применить префикс REPNE или REPNZ, то цикл будет выполняться пока в цепочке не встретится элемент, совпадающий с элементом в регистре AL/AX/EAX или пока не будет достигнут конец цепочки (содержимое CX/ECX равно 0).
То есть команда сканирования цепочки с префиксом REPE или REPZ позволяет найти элемент цепочки, отличающийся от заданного в аккумуляторе, а с префиксом REPNE или REPNZ – совпадающий по значению с элементом в аккумуляторе.
В листинге 4.2 в качестве примера показана программа, которая ищет символ 't' в строке. Если символ найден, то осуществляется переход на метку found.
Листинг 4.2 Поиск символа в строке (scastr.asm)
.model small
.stack 100h
.code
start: |
|
|
mov |
ax,@data |
|
mov |
ds,ax |
|
mov |
es,ax |
|
cld |
|
|
lea |
di,text1 |
; в DI адрес начала строки text1 |
mov |
cx,len_text1 |
; в CX длину строки text1 |
mov |
ah,0 |
|
mov |
al,'t' |
; ищем символ 't' в строке |
repne |
scasb |
|
je |
found |
|
mov |
dx,offset mes_no |
|
mov |
ah,9 |
|
int |
21h |
|
jmp |
exit |
|
found: |
|
|
mov |
dx,offset mes_yes |
|
mov |
ah,9 |
|
int |
21h |
|
exit: |
|
|
mov |
ax,4C00h |
|
int |
21h |
|
.data