
- •Программирование
- •Синтаксис языка Ассемблера
- •Xchg Приемник, Источник
- •Inc Операнд
- •Imul eax, b ; возможна потеря !!!
- •Idiv Источник
- •Стек. Команды работы со стеком
- •Подпрограммы
- •Структура приложения Win32 api
- •Функции Windows api Функции Windows api сохраняют значения регистров ebp, ebx, esi, edi и могут модифицировать регистры eax, ecx, edx
- •Int MessageBox (hwnd hWnd, char * сообщение, char * заголовок, int стиль) вывод диалогового окна с текстовым сообщением и одной-двумя-тремя кнопками (см. Тему«Стандартные диалоги»)
- •Int wsprintf (char * строка, char * образец, …) формирование текстовой строки по образцу
- •Int ReleaseDc(hwnd hWnd,hdc hDc) освободить заданный дескриптор контекста устройства, связанный с заданным окном
- •Арифметический сопроцессор
- •Void FloatToStr(double число, char * строка)
Подпрограммы
Подпрограмма часть программы, которая выполняет некоторую четко определенную операцию над данными, определяемыми параметрами.
Подпрограмма может быть вызвана из любой точки программы, и при каждом вызове в подпрограмму могут передаваться различные параметры.
После выполнения подпрограммы, управление передается в ту точку программы, из которой был осуществлен вызов.
Для работы с подпрограммами в системе команд микропроцессора предусмотрены две специализированные команды, относящиеся к группе команд передачи управления.
Главное отличие этих команд от команд перехода – возможность запомнить точку программы, из которой был сделан вызов подпрограммы и вернуться в эту точку.
Для сохранения информации о точке возврата используется стек. Это позволяет выполнять вложенные и рекурсивные вызовы подпрограмм.
Команда CALL – вызов подпрограммы
Формат команды
call Метка
Действие команды
push EIP ; запомнить точку возврата
jmp Метка ; перейти к подпрограмме
Команда RET – возврат из подпрограммы
Формат команды
ret
Действие команды
pop EIP ; вернуться в исходную точку
Порядок исполнения команд при вызове подпрограмм
основная программа:
. . .
. . .
call Подпрограмма
. . .
. . .
. . .
. . .
Подпрограмма:
. . .
. . .
ret
Подпрограммы могут располагаться в любом месте сегмента кода.
Поскольку процессор выполняет машинные команды последовательно одна за другой, он может «случайно» начать выполнение подпрограммы без её вызова с помощью команды CALL.
Поэтому необходимо обязательно предусмотреть «обход» подпрограммы, например, с помощью команды JMP.
Чтобы избежать возможных ошибок, подпрограммы следует располагать:
– в начале программы (до первой исполняемой команды);
– в конце программы (после команды, возвращающей управление операционной системе);
– в другом модуле.
Способы передачи параметров в подпрограмму
Существует несколько способов передачи параметров в подпрограмму:
– через регистры общего назначения;
– через общую память;
– через стек.
Эти же способы используются при возврате результатов работы подпрограммы.
Передача параметров подпрограммы через регистры
Перед вызовом подпрограммы значения параметров заносятся в регистры общего назначения.
Пример. Вычисление среднего двух чисел: C=(A+B)/2
Передача параметров подпрограммы через регистры
Достоинства метода: – просто; – быстро
Недостатки метода: – трудности с использованием регистров в подпрограмме (они заняты параметрами); – ограниченное количество параметров; – трудности с реализацией вложенных вызовов и рекурсии
Передача параметров подпрограммы через память
Перед вызовом подпрограммы значения параметров заносятся в ячейки памяти (например, массив).
Пример. Вычисление среднего двух чисел: C=(A+B)/2
Передача параметров подпрограммы через память
Достоинства метода: – неограниченное количество параметров, в том числе и переменное
Недостатки метода: – низкое быстродействие; – большие трудности с реализацией рекурсии или косвенной рекурсии
Передача параметров подпрограммы через стек
Перед вызовом подпрограммы значения параметров заносятся в стек.
Пример. Вычисление среднего двух чисел: C=(A+B)/2
push A
push B
push 0
call Srednee
pop C
add esp,8
Srednee:
mov eax,[esp+8]
add eax,[esp+12]
cdq
mov ebx,2
idiv ebx
mov [esp+4],eax
ret
Передача параметров подпрограммы через стек
Достоинства метода: – простота передачи параметров; – неограниченное количество параметров, в том числе и переменное; – легко организовываются вложенные и рекурсивные вызовы функций
Недостатки метода: – требуется внимательно следить за размещением параметров в стеке, особенно, когда он используется внутри подпрограммы; – требуется выравнивать стек после возврата из подпрограммы.
В языке программирования С используется комбинация двух способов передачи параметров:
– в подпрограмму параметры передаются через стек, причем справа-налево (т.е. первым в стеке сохраняется последний параметр, а первый параметр сохраняется последним);
– из подпрограммы результат возвращается в регистрах: 1 байт – в регистре AL; 2 байта – в регистре AX; 4 байта – в регистре EAX; 8 байт – в регистрах (EDX,EAX)
В функциях Windows API к этим соглашениям добавлено следующее:
– в функциях с фиксированным числом параметров (а таких подавляющее большинство) за выравнивание стека отвечает подпрограмма
Для этих целей используется расширенный вариант команды RET
Формат команды
ret число
В качестве операнда должен указываться общий размер (в байтах) всех параметров, помещенных в стек.
Действие команды
pop EIP ; вернуться в исходную точку add ESP, число ; выровнять стек на «число» байт
Набор соглашений по вызову функций в Win32 API называется STDCALL
Пример. Вычисление среднего двух чисел с использованием соглашения STDCALL
push B
push A
call Srednee
mov C,eax
Srednee:
mov eax,[esp+8]
add eax,[esp+4]
cdq
mov ebx,2
idiv ebx
ret 8
Одним из часто используемым применением стека является хранение локальных переменных, для чего в стеке организуется окно (кадр) локальных переменных.
Если обращаться к локальным переменным с помощью регистра ESP, требуется пересчитывать смещения параметров и переменных при любом его изменении.
В таких случаях используется регистр EBP – указатель кадра стека, значение которого остается неизменным. Следовательно, смещения параметров и переменных также фиксируются.
Типичный пролог в подпрограмме:
push ebp ; сохраняем исходное значение ebp
mov ebp,esp ; фиксируем текущий указатель
sub esp, размер ; делаем «окно» заданного размера
В результате получаем следующую конфигурацию стека:
Содержимое стека:
[EBP] – исходное значение EBP
[EBP+4] – адрес точки возврата
[EBP+8] – первый параметр
[EBP+12] – второй параметр
. . .
[EBP–4] – первая переменная
[EBP–8] – вторая переменная
. . .
Типичный эпилог в подпрограмме:
mov esp,ebp ; удаляем «окно» в стеке
pop ebp ; восстанавливаем исходное значение ebp
ret размер ; возврат + выравнивание стека