Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Проанализируем ассемблерные команды, показанные в окне отладчика. Для начала представим дизассемблированный фрагмент кода в более читабельном виде:
mov
mov
mov
mov
push
mov
call
mov
EAX, 3
EDX, -4
ESI, 1
EDI, 7
EDI
ECX, ESI
AddFour
ESI, EAX

Продолжив отладку программы, попадаем внутрь процедуры AddFour.

Нас будет интересовать код дизассемблированной процедуры, представленный в листинге 6.21.
Листинг 6.21. Код, сгенерированный отладчиком для процедуры AddFour push
mov
mov
add
EBP
EBP, ESP
EAX, EAX
EAX, EDX

add ЕАХ, ЕСХ
add ЕАХ, [ЕВР+8]
pop ЕВР
ret 4

Сравнивая последние два листинга, можно сделать следующие выводы:
ассемблерные процедуры в Delphi 7 по умолчанию используют соглашение о передаче параметров типа register. Как видно из листинга, первые три параметра передаются в регистрах Е А Х ( И ) , EDX(I2) И ЕСХСЕЗ).
Четвертый параметр 14 передается в регистре EDI через стек;
компилятор автоматически генерирует код пролога и эпилога, если для передачи параметров используется стек:
push ЕВР
mov ЕВР, ESP
pop ЕВР
ret 4
процедура возвращает результат в регистре ЕАХ.

Модифицируем исходный текст процедуры AddFour, точнее, строку с декларацией процедуры следующим образом:
function AddFour(il, i2, i3, i4: Integer): Integer; stdcaii;
Запустим приложение на отладку. Нас по-прежнему будут интересовать участки кода, где вызывается процедура AddFour. В первом окне вы видите фрагмент кода, где выполняется подготовка передачи параметров в процедуру
Интересующий нас фрагмент кода представлен далее в листинге 6.22.
Листинг 6.22. Передача параметров в процедуру AddFour с использованием соглашения s t d c a i i
mov ЕАХ, 3
mov EDX, -4
mov ESI, 1
mov EDI, 7
454 Глава 6
push EDI
push
push
push
call
mov
ESI
EDX
EAX
AddFour
ESI, EAX

Как видно из листинга, все параметры передаются через стек, причем последний параметр 14 попадает в стек первым. Возвращаемое процедурой значение помещается в регистр ЕАХ. Внутри самой процедуры параметры обрабатываются так, как показано в окне дизассемблера

Представим дизассемблированный текст в более читабельном виде (листинг 6.23).
Листинг 6.23. Обработка данных в процедуре AddFour для соглашения stdcaii
push ЕВР
mov ЕВР, ESP
mov ЕАХ, [ЕВР+8]
add ЕАХ, [ЕВР+12]
add ЕАХ, [ЕВР+16]
add ЕАХ, [ЕВР+20]
pop ЕВР
ret 16

Как и следовало ожидать (и это видно из последних двух листингов), передача параметров выполняется в соответствии с директивой stdcaii, причем компилятор генерирует весьма эффективный код! На основании дизассемб- лированных листингов можно сделать такой вывод: процедура, написанная полностью на встроенном ассемблере Delphi, практически эквивалентна отдельно написанному ассемблерному модулю. Теперь можно преобразовать процедуру вычисления суммы элементов целочисленного массива sumArray "смешанного" типа в полностью ассемблерный вариант. Она будет выглядеть так, как представлено в листинге 6.24.
Листинг 6.24. Ассемблерный вариант процедуры SumArray "смешанного" типа function SumArray(var iaddr; cnt: Integer): Pinteger;
asm
push ESI
mov ESI, DWORD PTR iaddr
mov ECX, DWORD PTR cnt
dec ECX
finit
fild DWORD PTR [ESI]
@L1:
fiadd DWORD PTR [ESI+4]
add ESI, 4
loop @L1
f istp
fwait
DWORD PTR isum
mov EAX, offset isum
pop ESI
end;

Рассмотрим более сложный пример ассемблерной процедуры. Пусть требуется найти сумму элементов массива, начиная с элемента и заканчивая к-м. Массив состоит из 7 вещественных чисел.

На главной форме приложения должны быть размещены поля редактирования Edit с именем Editl для вывода результата и кнопка Button. Вычисление суммы элементов выполняется в ассемблерной процедуре, возвращающей в качестве результата указатель на ячейку памяти, содержащую искомое значение. Обратите внимание, как передаются и используются параметры при вызове процедуры. Исходный текст программы приведен в листинге 6.25.
Листинг 6.25. Программа, выполняющая подсчет суммы элементов в определенном диапазоне изменения индекса массива
unit partsum;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForml = class(TForm)
Buttonl: TButton;
Editl : TEdit;
Edit2 : TEdit;
Edit3 : TEdit;
Labell : TLabel;
Label2 : TLabel;
Label3 : TLabel;
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Forml: TForml;
farray: array [1..7] of Single = (4.3, -1.2, 0.5, 7.45, -6.15,
12.3, -3.85);
fr, lr: Integer;
fsum: Single;
implementation
{$R *.dfm}
function SumReals(var fa; fr, lr:
asm
push ESI
mov ESI, DWORD PTR fa
mov EDX, DWORD PTR fr
mov ECX, DWORD PTR lr
Integer): PSingle;
sub ECX, EDX
shl EDX, 2
add ESI, EDX
f init
fid DWORD PTR
@L1:
fadd DWORD PTR [ESI+4]
add ESI, 4
loop @L1
fstp DWORD PTR fsum
fwait
mov EAX, offset fsum
pop ESI
end;
procedure TForml.ButtonlClick(Sender: TObject);
begin
fr := StrToInt(Editl.Text);
lr := StrToInt(Edit2.Text);
Edit3.Text := FloatToStrF((SumReals(farray, fr, 1г)л),
ffGeneral, 5, 7);
end;
end.


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru