Перейти к содержанию

Генерация компиляторами ассемблерных инструкций


Рекомендуемые сообщения

Привет, это вновь MasterGH с занудной, но полезной статьёй )

Рассмотрим работу с некоторыми FPU инструкциями компилятора Borland C++

Подопытная программка, которую я написал выглядит так:

post-3-1295709223,21_thumb.png

рис.1

(весит 12 кб в сжатом состоянии.. хе-хе, буду знать)

Как видите, она умеет уменьшать, увеличивать и уменьшать с условием значение здоровья типа float.

Основной код, который я добавил в приложение.


float fhealth = 100.0;
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
fhealth-=20.0;
updateValue();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
fhealth+=20.0;
updateValue();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
if (fhealth>10) {fhealth-=5;};
updateValue();
}

void TForm1::updateValue()
{
Edit1->Text=fhealth;
}

//---------------------------------------------------------------------------

Остальной код писать не буду, т.к. он генерируется автоматически. Ах да updateValue() нужно добавить в приватную область класса формы и больше я никакого кода не писал. А теперь взглянем на ассемблерные инструкции этих действий.

Буду приводить кусок исходника и описание.

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
fhealth-=20.0;
updateValue();
}

Это тоже самое что:

post-3-1295709226,8_thumb.png

рис.2

Так как всё тут просто комментировать не буду.

Идём к следующей инструкции.

//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
fhealth+=20.0;
updateValue();
}

Почти аналогично, только с инструкцией добавления:

post-3-1295709230,84_thumb.png

рис.3

Ну, а теперь самое интересное:

//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
if (fhealth>10) {fhealth-=5;};
updateValue();
}

А теперь разберём инструкции подробнее:

Unit1.cpp.32: if (fhealth>10) {fhealth-=5;};

00401CF8 D90598414000 fld dword ptr [$00404198] //грузим в стек FPU 100.0

00401CFE D9052C1D4000 fld dword ptr [$00401d2c] // грузим в стек FPU 5.0

//Сейчас ST(0)=10, а ST(1)=100

00401D04 D9C9 fxch st(1) // меняет местами содержимое регистров

//Сейчас ST(0)=100, а ST(1)=10

00401D06 DAE9 fucompp // сравнивание с двойным выталкиванием из стека

//Сейчас ST(0)=Empty, а ST(1)= Empty (что означает пустые)

Флаги FPU поменялись

Было/стало

post-3-1295709235,95_thumb.png

рис.4

00401D08 DFE0 fstsw ax

Лезу в справку:

fstsw и fnstsw сохраняют текущее значение слова статуса FPU в указанном месте. Операндом-адресатом может быть либо 16 бит в памяти, либо регистр AX. fstsw перед сохранением слова проверяет на подвешенные немаскируемые прерывания, fnstsw этого не делает

Короче какие-то флаги FPU загнали в AX

post-3-1295709240,3_thumb.png

рис.5

00401D0A 9E sahf // загружаем ah в младший байт регистра eflags

post-3-1295709245,17_thumb.png

рис.6

00401D0B 7612 jbe $00401d1f // jbe не работает когда 10<100 при флагах CPU: CF=1 и ZF=1

// а теперь вы полнение записи здоровья

00401D0D D905301D4000 fld dword ptr [$00401d30] // грузим 5 в ST(0)

00401D13 D82D98414000 fsubr dword ptr [$00404198] // от здоровья отнимаем ST(0) и сохраняем здоровье в ST(0)

00401D19 D91D98414000 fstp dword ptr [$00404198] // выталкиваем и записываем вновь здоровье

Unit1.cpp.33: updateValue();

00401D1F FF75FC push dword ptr [ebp-$04]

00401D22 E80D000000 call TForm1::updateValue() // ну, а это уже пошла моя функция обновления…

00401D27 59 pop ecx

Заключение.

Короче говоря, берём на зуб:

Unit1.cpp.32: if (fhealth>10) {fhealth-=5;};
00401CF8 D90598414000 fld dword ptr [$00404198]// fhealth
00401CFE D9052C1D4000 fld dword ptr [$00401d2c]// 10.0
00401D04 D9C9 fxch st(1)
00401D06 DAE9 fucompp
00401D08 DFE0 fstsw ax
00401D0A 9E sahf
00401D0B 7612 jbe $00401d1f // if (fhealth>10) {fhealth-=5;};
00401D0D D905301D4000 fld dword ptr [$00401d30]
00401D13 D82D98414000 fsubr dword ptr [$00404198]
00401D19 D91D98414000 fstp dword ptr [$00404198]

Unit1.cpp.33: updateValue();
00401D1F FF75FC push dword ptr [ebp-$04]

Этот шаблон вы можете применить в своих скриптах, когда некоторый параметр не должен быть меньше другого некоторого параметра.

Не знаю как вы, я подумал сложные скрипты лучше писать на С++ реализованные в dll, которые можно подгрузить скриптами CE, но об этом позже...

Ссылка на комментарий
Поделиться на другие сайты

  • 6 лет спустя...
On 28.03.2010 at 6:06 PM, MasterGH said:

А теперь разберём инструкции подробнее:

Unit1.cpp.32: if (fhealth>10) {fhealth-=5;};

00401CF8 D90598414000 fld dword ptr [$00404198] //грузим в стек FPU 100.0

00401CFE D9052C1D4000 fld dword ptr [$00401d2c] // грузим в стек FPU 5.0

 

Кажется тут в комментариях должно было быть "грузим в стек FPU 10.0" вместо "грузим в стек FPU 5.0"

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.