8.3.4. Выравнивание
80-битные данные должны быть выравнены по 16-байтным границам (то есть четыре младших бита адреса должны быть равны нулю).
Восьмибайтные данные должны быть выравнены по восьмибайтным границам (то есть три младших бита адреса должны быть равны нулю).
Четырёхбайтные данные должны быть выравнены по границе двойного слова (то есть два младших бита адреса должны быть равны нулю).
Двухбайтные данные должны быть выравнены по границе слова.
Метки для переходов, особенно метки, отмечающие начало цикла, должны быть выравнены по 16-байтным границам.
Каждое невыравненное обращение к данным означает потерю тактов процессора.
Для выравнивания данных и кода используется директива ALIGN:
ALIGN <число>
Число должно быть степенью двойки. Данные и команда, расположенные после директивы ALIGN, будут размещены по адресу, кратному указанному числу.
9. Примеры
Процедура вычисления наибольшего общего делителя двух беззнаковых чисел. Для нахождения НОД используется алгоритм Евклида: пока числа не равны, надо вычитать из большего числа меньшее. Процедура получает параметры через регистры EAX и EDX и возвращает результат через регистр EAX.
NOD proc N1: cmp eax, edx ; Сравниваем числа je N3 ; Если числа равны, завершаем работу процедуры ja N2 ; Если первое число больше, обходим обмен ; Поскольку команды перехода не меняют флаги, оба перехода ; выполняются или не выполняются по результатам одного сравнения xchg eax, edx ; Если первое число было меньше, выполняем обмен N2: sub eax, edx ; Вычитаем из большего числа меньшее jmp N1 ; Переход к началу цикла N3: ret NOD endp
Ввод и вывод в консольном приложении. В программе используются следующие функции Win32 API.
SetConsoleTitle – меняет заголовок окна консоли. Получает один параметр – указатель на строку, которая будет выведена в заголовке. Строка должна заканчиваться нулём.
GetStrHandle – возвращает идентификатор устройства ввода, устройства вывода или устройства отчёта об ошибках. Для консольного приложения всё три устройства являются консолью, но идентификаторы будут разными. Функция получает один параметр – указание, идентификатор какого устройства нужно вернуть. Чтобы получить идентификатор устройства ввода, надо передать функции число -10, чтобы получить идентификатор устройства вывода – число -11, а чтобы получить идентификатор устройства отчёта об ошибках – число -12. Функция возвращает требуемый идентификатор через регистр EAX.
WriteConsole – выводит строку в консоль. Получает следующие параметры – идентификатор устройства вывода, адрес выводимой строки, количество символов для вывода, адрес переменной, куда будет записано количество выведенных символов, зарезервированный указатель.
ReadConsole – вводит строку из консоли. Получает следующие параметры – идентификатор устройства ввода, адрес памяти, куда будет записана введённая строка, максимальное количество читаемых символов, адрес переменной, куда будет записано реальное количество введённых символов, зарезервированный указатель.
Не забывайте, что параметры кладутся в стек, начиная с последнего, и что введённая строка всегда будет содержать в конце символы с кодами 13 и 10, которые появляются при нажатии на клавишу ВВОД (без чего, однако, ввод не завершится).
.686 .model flat, c option casemap: none include \masm32\include\windows.inc include \masm32\include\kernel32.inc includelib \masm32\lib\kernel32.lib .data str db 256 dup(0) hStdIn dd 0 hStdOut dd 0 slength dd 0 .const sConsoleTitle db 'Input and Output',0 ; Заголовок окна консоли. Заканчивается нулём prompt db 'Input a string', 13,10 ; Приглашение для ввода. Символы с кодами 13 и 10 ; обеспечивают перевод курсора на следующую строку STD_INPUT_HANDLE equ -10d ; Определяем символические имена для констант, STD_OUTPUT_HANDLE equ -11d ; указывающих требуемое устройство .code program: ; Вывод заголовка консоли push offset sConsoleTitle ; Кладём в стек адрес начала строки заголовка консоли call SetConsoleTitle ; Вызываем функцию ; Получаем идентификатор устройства ввода push STD_INPUT_HANDLE ; Кладём в стек параметр функции GetStdHandle call GetStdHandle ; Вызываем функцию mov hStdIn, eax ; Сохраняем полученный идентификатор ; Получаем идентификатор устройства вывода push STD_OUTPUT_HANDLE call GetStdHandle mov hStdOut, eax ; Выводим приглашение push 0 ; Зарезервированный параметр, в стек кладём 0 push 0 ; Указатель на переменную для записи количества выведенных символов, ; в данном случае не нужен, поэтому в стек кладём 0 push 10h ; Количество выводимых символов push offset prompt ; Адрес выводимой строки push hStdOut ; Идентификатор устройства вывода call WriteConsole ; Вызываем функцию ; Вводим строку push 0 ; Зарезервированный параметр, в стек кладём 0 push offset slength ; Адрес переменной, куда будет записано количество введённых символов push 256 ; Максимальное количество вводимых символов push offset str ; Адрес для записи введённой строки push hStdIn ; Идентификатор устройства ввода call ReadConsole ; Вызываем функцию ; Выводим строку push 0 push 0 push slength push offset str push hStdOut call WriteConsole ; Задержка push 1800h call Sleep push 0 call ExitProcess end program
Do'stlaringiz bilan baham: |