7.9. Рекурсивные процедуры
Рекурсия – ресурсоёмкий способ реализации алгоритмов. Она требует много места для хранения локальных данных на каждом шаге рекурсии, кроме того, рекурсивные процедуры обычно выполняются не очень быстро. Поэтому языку ассемблера, предназначенному для написания быстрых программ, рекурсия, в общем, не свойственна. Но при желании и на ассемблере можно написать рекурсивную процедуру. Принципы реализации рекурсивной процедуры на языке ассемблера такие же, как и на других языках. В процедуре должна быть терминальная ветвь, в которой нет рекурсивного вызова, и рабочая ветвь.
При реализации рекурсивных процедур становится особенно важным использование стека для передачи параметров и адреса возврата, что позволяет хранить данные, относящиеся к разным уровням рекурсивных вызовов, в разных областях памяти.
Для примера рассмотрим рекурсивную процедуру вычисления факториала целого беззнакового числа. Процедура получает параметр через стек и возвращает результат через регистр EAX.
factorial proc mov eax, [esp + 4] ; Заносим в регистр EAX параметр процедуры test eax, eax ; Проверяем значение в регистре EAX jz L1 ; Если EAX = 0, то обходим рекурсивную ветвь dec eax ; Уменьшаем значение в регистре EAX на 1 push eax ; Кладём в стек параметр для следующего рекурсивного вызова call factorial ; Вызываем процедуру add esp, 4 ; Очищаем стек, т.к. процедура использует RET без параметров mul dword ptr [esp + 4] ; Умножаем EAX, хранящий результат предыдущего вызова, на параметр текущего вызова процедуры ret ; Возврат из процедуры (без параметров) L1: inc eax ; Если EAX был равен 0, записываем в EAX единицу L2: ret ; Возврат из процедуры (без параметров) factorial endp
8. Оптимизация программ, написанных на языке ассемблера
Наиболее популярным применением ассемблера обычно считается именно оптимизация программ, то есть уменьшение времени выполнения программ по сравнению с языками высокого уровня. Но если просто переписать текст, например с языка С на ассемблер, переводя каждую команду наиболее очевидным способом, часто оказывается, что процедура на языке С выполняется быстрее. Вообще говоря, ассемблер, как и любой другой язык, сам по себе не является панацеей от неэффективного программирования – чтобы действительно оптимизировать программу, требуется не только знание команд процессора, но и знание алгоритмов, навык оптимальных способов их реализации и подробная информация об архитектуре процессора.
Проблему оптимизации принято делить на три основных уровня:
выбор наиболее оптимального алгоритма – высокоуровневая оптимизация;
наиболее оптимальная реализация алгоритма – оптимизация среднего уровня;
подсчёт тактов, тратящихся на выполнение каждой команды, и оптимизация их порядка для конкретного процессора – низкоуровневая оптимизация.
Do'stlaringiz bilan baham: |