Читать онлайн «BASM. Уроки для начинающих»

Автор Дамаскин Христенсен

тей и оформлен в виде книге в формате Word 2000. В данный момент в книгу вошло 7 примеров. Общее для этих статей и для тех, что в процессе подготовки то, что они объясняют некоторые вопросы использования BASM на примерах функций. Большинство из этих функций сначала реализуются на Паскале, затем сгенерированный компилятором ассемблерный код, копируется из окна CPU view в Delphi, затем анализируется и оптимизируется. Иногда оптимизация включает в себя и использование инструкций MMX, SSE или SSE2.
В самом начале рассматривается код сделанный компилятором, в котором использует только наиболее используемые инструкции из огромного набора инструкций 32-битной архитектуры Intel. Просматривая, сгенерированный компилятором код, мы получаем представление и об эффективности компилятора, в общем, и о компиляторе Delphi в целом.
Когда применимо, то приводятся обобщения по оптимизации ассемблерного кода. Эта общая оптимизация применима к компиляторам и большинство компиляторов, включая Delphi, ее имеют. Когда ни будь, в будущем будет разработан инструмент по автоматической оптимизации ассемблерного кода.
Знание об используемом процессоре очень необходимы при оптимизации кода и поэтому также разъясняются множество подробностей о CPU, таких как например конвейеры.
Насколько Я знаю, имеется очень мало литературы, в которой объясняются все эти особенности, на уровне, который был бы понятен начинающим. Я надеюсь, что эта серия статей сможет помочь им в этом.

С уважением,
Денис Христенсен Dennis Kjaer Christensen.

Lesson 1
Начнем с небольшого примера. Это простая функция Паскаля по умножению целого на константу 2.

function MulInt2(I : Integer) : Integer;
begin
Result := I * 2;
end;
Посмотрим сгенерированный код в окне CPU view. Я компилировал с включенной оптимизацией.
function MulInt2_BASM(I : Integer) : Integer;
begin
Result := I * 2;
{
add eax,eax
ret
}
end;
Здесь мы видим, что параметр передается в функцию в регистре EAX и результат возвращается в том же регистре. Это соглашение по передаче параметров через регистры (register calling convention), которое является соглашением по умолчанию в Delphi. Актуальный код очень простой, умножение на 2 заменяется сложением операнда с самим собой, I + I = 2I. Инструкция RET возвращает управление в строку, следующую за вызовом функции.
Сделаем тот же код, как чистую asm функцию.
function MulInt2_BASM2(I : Integer) : Integer;
asm
//Result := I * 2;
add eax,eax
//ret
end;
Заметим, что возврат из функции обеспечивается встроенным ассемблером.
Теперь посмотрит на код вызова функции.
Вот Паскаль код:
procedure TForm1. Button1Click(Sender: TObject);
var
I, J : Integer;

begin
I := StrToInt(IEdit. Text);
J := MulInt2_BASM2(I);
JEdit. Text := IntToStr(J);
end;
Важная для нас строка следующая
J := MulInt2_BASM2(I);
В окне CPU мы видим
call StrToInt
call MulInt2_BASM2
mov esi,eax
После вызова StrToInt из строки выше вызова нашей функции, I находится в регистре EAX. (StrToInt также следует соглашению о передаче параметров через регистры).