- •Содержание
- •Введение
- •ДЕНЬ 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 |
154 |
|
.data |
|
|
hello_mess |
db "Первая программа под Windows на ассемблере", 0 |
|
hello_title |
db "Hello, World!", 0 |
|
.code |
|
|
start: |
|
|
push |
MB_OKCANCEL |
|
push |
offset hello_title |
|
push |
offset hello_mess |
|
push |
0 |
|
call |
MessageBoxA |
|
push |
0 |
|
call |
ExitProcess |
|
end start
7.2.1. Директива INVOKE
Вы можете для вызова API-функций использовать директиву INVOKE, которая позволяет записывать вызовы в более удобном виде. Например, следующий вызов:
push MB_OKCANCEL
push offset hello_title push offset hello_mess push 0
call MessageBoxA
с помощью директивы INVOKE будет записан следующим образом:
invoke MessageBoxA,0,addr hello_mess,addr hello_title, MB_OKCANCEL
Вызов функции ExitProcess можно записать следующим образом: invoke ExitProcess, 0
В директиве INVOKE можно использовать оператор ADDR вместо OFFSET. Далее в примерах кода мы будем использовать директиву INVOKE.
7.3. Консольное приложение
Хотя Windows является графической оконной системой, но вместе с тем она позволяет создавать консольные приложения, т. е. приложения которые подобно DOS-приложениям работают с командной строкой. Для создания консольных приложений в Windows существуют специальные API-функции.
Ввод и вывод в консоли выполняется с помощью функций ReadConsole и WriteConsole соответственно:
BOOL WINAPI WriteConsole(
HANDLE hConsoleOutput, const VOID* lpBuffer,
DWORD nNumberOfCharsToWrite, LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved
);
Параметры функции:
hConsoleOutput — дескриптор стандартного потока вывода;
http://www.sklyaroff.ru |
155 |
lpBuffer — указатель на строку которую нужно вывести;
nNumberOfCharsToWrite — число символов строки, которые нужно вывести;
lpNumberOfCharsWritten — указатель на переменную DWORD, куда будет помещено количество действительно выведенных символов после выполнения функции;
lpReserved — зарезервированный параметр для использования в будущем, поэтому должен быть равен нулю.
BOOL WINAPI ReadConsole(
HANDLE hConsoleInput, LPVOID lpBuffer,
DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved
);
Параметры функции:
hConsoleInput — дескриптор стандартного потока ввода;
lpBuffer — указатель на буфер, в который будет записана принятая строка;
nNumberOfCharsToRead — максимальное число символов, которые будут приняты;
lpNumberOfCharsRead — число фактически считанных символов;
lpReserved — зарезервированный параметр для использования в будущем, поэтому должен быть равен нулю.
Дескрипторы ввода-вывода необходимо получить с помощью функции GetStdHandle:
HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
Параметр nStdHandle может иметь одно из трех значений:
STD_INPUT_HANDLE equ -10 STD_OUTPUT_HANDLE equ -11 STD_ERROR_HANDLE equ -12
Эти идентификаторы определены в файле WINDOWS.INC.
В листинге 7.2 показана простейшая программа, которая просит пользователя ввести свое имя и затем приветствует его по имени, например:
Your name: Ivan Sklyaroff Hello, Ivan Sklyaroff
С помощью API-функции
BOOL WINAPI SetConsoleTitle(LPCTSTR lpConsoleTitle);
мы выводим в заголовке консоли фразу "DEMO CONSOLE PROGRAM".
Единственный аргумент этой функции — адрес строки символов, которая будет выведена в заголовке окна консоли.
Компиляция:
ml /c /coff /Cp conwin.asm
link.exe /SUBSYSTEM:CONSOLE /LIBPATH:d:\masm32\lib conwin.obj
Листинг 7.2. Консольная программа под Windows (conwin.asm)
.386
.model flat,stdcall
include \masm32\include\windows.inc include \masm32\include\kernel32.inc
http://www.sklyaroff.ru |
|
156 |
|||
includelib \masm32\lib\kernel32.lib |
|
|
|||
|
.const |
|
|
|
|
ConsoleTitle |
db |
"DEMO CONSOLE PROGRAM",0 |
|||
|
.data |
|
|
|
|
msg1 |
db |
"Your name: " |
|
|
|
msg1_len = $-msg1 |
|
|
|
||
msg2 |
db |
"Hello, " |
|
|
|
msg2_len = $-msg2 |
|
|
|
||
InputBuffer |
db |
100 dup (?) |
; буфер для ввода |
||
len_InputBuffer = $-InputBuffer |
|
|
|||
|
.data? |
|
|
|
|
hOutputdd |
? |
; хендл для вывода |
|||
hInput |
dd |
? |
; хендл для ввода |
||
nRead |
dd |
? |
; прочитано байт |
||
nWritendd |
? |
; напечатано байт |
.code
start:
invoke SetConsoleTitleA,addr ConsoleTitle
; получаем хендл для вывода
invoke GetStdHandle,STD_OUTPUT_HANDLE mov hOutput,eax
invoke WriteConsoleA,hOutput,addr msg1,msg1_len,addr nWriten,NULL
; получаем хендл для ввода
invoke GetStdHandle,STD_INPUT_HANDLE mov hInput,eax
invoke ReadConsoleA,hInput,addr InputBuffer,len_InputBuffer,addr nRead,NULL
invoke WriteConsoleA,hOutput,addr msg2,msg2_len,addr nWriten,NULL
invoke WriteConsoleA,hOutput,addr InputBuffer,nRead,addr nWriten,NULL
invoke ExitProcess,0
end start
В листинге 7.3 показано еще одно консольное приложение. Данная Windowsпрограмма является аналогом MS-DOS программы из листинга 5.2, которая складывает два вещественных числа с плавающей запятой.
Кроме функции FpuFLtoA все остальные функции в этой программе вам уже знакомы. Функция FpuFLtoA предназначена для вывода вещественного числа (в нашем случае результат сложения вещественных чисел) на экран. Данная функция не является API-функцией, а является внутренней MASM32-функцией и входит в специальную библиотеку FPU.LIB, которая подключается в начале нашей программы также как и остальные библиотеки. Подробное описание функции на английском языке можно найти в справке MASM32, которая обычно располагается в каталоге
\masm32\help\fpuhelp.chm.
http://www.sklyaroff.ru |
157 |
Функция FpuFLtoA может работать только с 80-битовыми числами и имеет четыре параметра:
FpuFLtoA ( lpSrc1 lpSrc2 lpszDest uID
)
lpSrc1 — адрес 80-битового числа, которое будет выводиться на экран (этот параметр игнорируется, если uID имеет значение SRC1_FPU);
lpSrc2 — беззнаковое целое указывающее количество десятичных знаков после запятой или адрес беззнакового целого (в зависимости от параметра uID);
lpszDest — адрес буфера, куда будут записаны символы, в которые преобразуется число. Буфер должен быть достаточно большим, чтобы вместить возвращаемые символы. Самое большое число может иметь 17 символов перед знаком десятичной точки, знак десятичной точки, 15 десятичных цифр после точки, и завершающий нуль (таким образом, максимум 34 символа);
uID — флаги, управляющие работой функции. Один из флагов SRC1_? может объединяться с помощью операции OR только с одним из SRC2_? и одним из STR_? флагов (Флаг STR_REG не нужно объединять оператором OR, если строка должна быть возвращена в десятичном формате; потому что по умолчанию так).
uID флаги и их назначение:
SRC1_FPU — первый параметр функции Src не используется (уже на FPU);
SRC1_REAL — первый параметр Src должен быть адресом 80-битного числа хранящегося в обычной памяти;
SRC2_DMEM — второй параметр Src2 должен быть адресом 32-битного беззнакового числа;
SRC2_DIMM — второй параметр Src2 должен быть простым 32-битным беззнаковым числом;
STR_REG — строка должна быть возвращена в десятичном формате;
STR_SCI — строка должна быть возвращена в научном формате. Компиляция:
ml /c /coff /Cp fpuconwin.asm
link.exe /SUBSYSTEM:CONSOLE /LIBPATH:d:\masm32\lib fpuconwin.obj
Листинг 7.3. Консольная программа под Windows складывающая два вещественных числа (fpuconwin.asm)
.386
.model flat,stdcall option casemap:none
include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\fpu.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\kernel32.lib includelib \masm32\lib\fpu.lib
BSIZE |
equ |
30 |
|
|
.data |
|
|
num1 |
dd |
45.56 |
; первое вещественное число |
num2 |
dd |
30.13 |
; второе вещественное число |