• Объявления

    • Garik66

      Пользователям форума   05.11.2017

      Прошу обратить внимание на эту тему (чтобы увидеть ссылку, войдите в объявление - нажмите на заголовок):   
MasterGH

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

3 сообщения в этой теме

Привет, это вновь 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, но об этом позже...

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
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"

0

Поделиться сообщением


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

Я уже исправлять не буду, Пусть как есть.


Шесть прошло с момента поста. Даже не верится.


 

1

Поделиться сообщением


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

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас