Директива
|
Порядок
передачи параметров
|
Освобождение
стека
|
Передача
параметров через регистры
|
register,
fastcall fastcall
|
Слева
направо
|
Процедура
|
ЕАХ,
EDX, ЕСХ
|
pascal
|
Слева
направо
|
Процедура
|
cdecl
|
Справа
налево
|
Вызывающая
программа
|
Нет
|
stdcall
|
Справа
налево
|
Процедура
|
Нет
|
safecall
|
Справа
налево
|
Процедура
|
Нет
|
Порядок передачи параметров для каждой директивы
указывает компилятору, каким образом параметры передаются в вызываемую
процедуру. Для директив pascal, cdecl, stdcallи safecallпараметры передаются
через стек, а при использовании директив registerили fastcall- через регистры.
Перед возвращением в основную программу
необходимо восстановить указатель стека. Это относится кдирективам pascal,
cdecl, stdcallиsafecall. Что касается применения тех или иных способов вызова
внешних процедур, то здесь не существует однозначных рецептов. Если вы
работаете с APIфункциями Windows, то для них стандартным способом вызова
является stdcallили safecall. Директиву cdeclлучше использовать для вызова
процедур и функций из программ, написанных в C++.
Наиболее быстрым способом передачи параметров
является регистровый(register, или fastcall). Директива registerиспользуется в
большинстве языков высокого уровня, но разработчики Microsoftрешили назвать ее
по- другому, и в VisualC++ она определяется иначе - fastcall. Стек в этом
случае не используется, поэтому мы получаем выигрыш по скорости выполнения
подпрограммы.
Директива pascalиспользуется редко и только в
целях обратной совместимости(backwardcompatibility).
Все подпрограммы возвращают результат (значение
или адрес) в регистре ЕАХ.
Отдельно компилируемые модули
Разработаем программу на языке высокого уровня,
вызывающую процедуру subtwo (передача параметров через стек, по значению).
Delphi 7:.pas;
Windows, Messages, SysUtils,
Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
TForm1 = class(TForm)
I1Edit: TEdit;
Label1: TLabel;
I2Edit: TEdit;
Label2: TLabel;: TEdit;
Label3: TLabel;
Button1: TButton;Button1Click(Sender:
TObject);
{ Private declarations }
{ Public declarations };
Form1: TForm1;
{$R *.dfm}
{$L subtwo.obj}(i1:Integer;
i2:Integer):Integer;stdcall;external;TForm1.Button1Click(Sender: TObject);
I1, I2: Integer;
I1:= StrToInt(I1Edit.Text);
I2:= StrToInt(I2Edit.Text);.Text:=
IntToStr(subtwo(I1, I2));
//;..asm
.386
.model flat
.data
.code, ESP, DWORD PTR [EBP+8], DWORD
PTR [EBP+12]
Скриншот:
Visual C++ . Net:TWO INTS IN
C.NETDlg.cpp
#include "stdafx.h"
#include "SUBSTRACTION TWO INTS
IN C.NET.h"
#include "SUBSTRACTION TWO INTS
IN C.NETDlg.h""C" int _stdcallsubtwo(int i1, int i2);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App
About: public CDialog
{:();
// Dialog Data{ IDD = IDD_ABOUTBOX
};
protected:
virtual void
DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation:_MESSAGE_MAP()
};::CAboutDlg() :
CDialog(CAboutDlg::IDD)
{
}::DoDataExchange(CDataExchange*
pDX)
{::DoDataExchange(pDX);
}_MESSAGE_MAP(CAboutDlg,
CDialog)_MESSAGE_MAP()
// CSUBSTRACTIONTWOINTSINCNETDlg
dialog::CSUBSTRACTIONTWOINTSINCNETDlg(CWnd* pParent /*=NULL*/)
:
CDialog(CSUBSTRACTIONTWOINTSINCNETDlg::IDD, pParent)
, I1(0)
, I2(0)
, iSubResult(0)
{_hIcon =
AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}::DoDataExchange(CDataExchange*
pDX)
{::DoDataExchange(pDX);_Text(pDX,
IDC_EDIT1, I1);_Text(pDX, IDC_EDIT2, I2);_Text(pDX, IDC_EDIT3, iSubResult);
//}}AFX_MSG_MAP_BN_CLICKED(IDC_BUTTON1,
OnBnClickedButton1)_MESSAGE_MAP()
// CSUBSTRACTIONTWOINTSINCNETDlg
message handlersCSUBSTRACTIONTWOINTSINCNETDlg::OnInitDialog()
{::OnInitDialog();
// Add "About..." menu
item to system menu.
// IDM_ABOUTBOX must be in the
system command range.((IDM_ABOUTBOX & 0xFFF0) ==
IDM_ABOUTBOX);(IDM_ABOUTBOX < 0xF000);* pSysMenu =
GetSystemMenu(FALSE);(pSysMenu != NULL)
{;.LoadString(IDS_ABOUTBOX);(!strAboutMenu.IsEmpty())
{>AppendMenu(MF_SEPARATOR);>AppendMenu(MF_STRING,
IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The
framework does this automatically
// when the application's main
window is not a dialog(m_hIcon, TRUE);// Set big icon(m_hIcon, FALSE);// Set
small icon
// TODO: Add extra initialization
hereTRUE; // return TRUE unless you set the focus to a control
}::OnSysCommand(UINT nID, LPARAM
lParam)
{((nID& 0xFFF0) == IDM_ABOUTBOX)
{;.DoModal();
}
{::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to
your dialog, you will need the code below
// to draw the icon. For MFC
applications using the document/view model,
// this is automatically done for
you by the framework.::OnPaint()
{(IsIconic())
{(this); // device context for
painting(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()),
0);
// Center icon in client rectangle=
GetSystemMetrics(SM_CXICON);= GetSystemMetrics(SM_CYICON);;(&rect);x =
(rect.Width() - cxIcon + 1) / 2;y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon.DrawIcon(x, y,
m_hIcon);
}
{::OnPaint();
}
}
// The system calls this function to
obtain the cursor to display while the user drags
// the minimized
window.CSUBSTRACTIONTWOINTSINCNETDlg::OnQueryDragIcon()
{_cast<HCURSOR>(m_hIcon);
}::OnBnClickedButton1()
{
// TODO: Add your control
notification handler code here(TRUE);= subtwo(I1, I2);(FALSE);
}.asm
.386
.model flat_subtwo@8
.data
.code
_subtwo@8 proc, ESP, DWORD PTR
[EBP+8], DWORD PTR [EBP+12]
_subtwo@8 endp
Найти максимальное значение в массиве целых
чисел (передача параметров через стек, по ссылке).
Delphi 7:.pas;
Windows, Messages, SysUtils,
Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;Button1Click(Sender:
TObject);(Sender: TObject);
{ Private declarations }
{ Public declarations };
Form1: TForm1;
I1:array [1..12] of integer =
(585,1751,-27,-76,312, 93, 5, -1, 57, 22,-5, 997);
SI1: Integer;: PInteger;
Max: Integer;
{$R *.dfm}
{$L
maxint.obj}(PI1:PInteger;SI1:Integer):PInteger;stdcall;external;TForm1.Button1Click(Sender:
TObject);:= maxint(@I1,SI1);
Max:=pMax^;
Edit2.Text:=
IntToStr(Max);;TForm1.FormCreate(Sender: TObject);:Integer;
SI1:= SizeOf(I1) div 4;:= 1 to SI1
do
Edit1.Text:= Edit1.Text + ' ' +
IntToStr(I1[Cnt]);;..asm
.386
.model flat
.data
.code, ESP, DWORD PTR [EBP+16] ;
first.parm - right - size , DWORD PTR [EBP+12] ; sec.parm - left - address of
array_cmp: , DWORD PTR [ESI], DWORD PTR [ESI+4]_cnt, DWORD PTR [ESI+4]_cnt:, 0,
4_cmp:, ESI
maxintendp
Visual C++ . Net:Max Integer in
ArrayDlg.cpp
#include "stdafx.h"
#include "Find Max Integer in
Array.h"
#include "Find Max Integer in
ArrayDlg.h""C" int* _stdcallmaxval(int *pi1, int si1);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App
About: public CDialog
{:();
// Dialog Data{ IDD = IDD_ABOUTBOX
};:void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation:_MESSAGE_MAP()
};::CAboutDlg() :
CDialog(CAboutDlg::IDD)
{
}::DoDataExchange(CDataExchange*
pDX)
{::DoDataExchange(pDX);
}_MESSAGE_MAP(CAboutDlg,
CDialog)_MESSAGE_MAP()
// CFindMaxIntegerinArrayDlg dialog::CFindMaxIntegerinArrayDlg(CWnd*
pParent /*=NULL*/)
:
CDialog(CFindMaxIntegerinArrayDlg::IDD, pParent)
{_hIcon =
AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}::DoDataExchange(CDataExchange*
pDX)
{::DoDataExchange(pDX);
}_MESSAGE_MAP(CFindMaxIntegerinArrayDlg,
CDialog)_WM_SYSCOMMAND()_WM_PAINT()_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP
//ON_WM_CREATE()
//ON_WM_ACTIVATE()_WM_LBUTTONDOWN()_MESSAGE_MAP()
// CFindMaxIntegerinArrayDlg message
handlersCFindMaxIntegerinArrayDlg::OnInitDialog()
{::OnInitDialog();
// Add "About..." menu
item to system menu.
// IDM_ABOUTBOX must be in the
system command range.((IDM_ABOUTBOX & 0xFFF0) ==
IDM_ABOUTBOX);(IDM_ABOUTBOX < 0xF000);* pSysMenu =
GetSystemMenu(FALSE);(pSysMenu != NULL)
{;.LoadString(IDS_ABOUTBOX);(!strAboutMenu.IsEmpty())
{>AppendMenu(MF_SEPARATOR);>AppendMenu(MF_STRING,
IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The
framework does this automatically
// when the application's main
window is not a dialog(m_hIcon, TRUE);// Set big icon(m_hIcon, FALSE);// Set
small icon
// TODO: Add extra initialization
hereTRUE; // return TRUE unless you set the focus to a control
}::OnSysCommand(UINT nID, LPARAM
lParam)
{((nID& 0xFFF0) == IDM_ABOUTBOX)
{;.DoModal();
}
{::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to
your dialog, you will need the code below
// to draw the icon. For MFC
applications using the document/view model,
// this is automatically done for
you by the framework.::OnPaint()
{(IsIconic())
{(this); // device context for
painting(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()),
0);
// Center icon in client rectangle=
GetSystemMetrics(SM_CXICON);= GetSystemMetrics(SM_CYICON);;(&rect);x =
(rect.Width() - cxIcon + 1) / 2;y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon.DrawIcon(x, y,
m_hIcon);
}
{::OnPaint();
}
}
// The system calls this function to
obtain the cursor to display while the user drags
// the minimized
window.CFindMaxIntegerinArrayDlg::OnQueryDragIcon()
{_cast<HCURSOR>(m_hIcon);
}::OnLButtonDown(UINT nFlags, CPoint
point)
{
// TODO: Add your message handler
code here and/or call defaulti1[10] = {674, 7, 90, -34, 2, -596, -45, 76, -12,
64};[8];(this);rect;(&rect);(intcnt = 0;cnt <sizeof(i1)/4;cnt++)
{.TextOut((rect.right -
rect.left)/30 + cnt*45 , (rect.bottom - rect.top )/ 4 , itoa(i1[cnt],buf,10));
};= *maxval(i1,
sizeof(i1)/4);.TextOut((rect.right - rect.left)/2 - 40 , (rect.bottom -
rect.top )/2 + 30 , itoa(ires, buf,10));
::OnLButtonDown(nFlags, point);
}.asm
.386
.model flat_maxval@8
.dataDD 0
.code
_maxval@8 endp
Встроенный ассемблер
Найти сумму двух целых чисел:
basm1pas.pasbasm1pas;
Windows, Messages, SysUtils,
Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
TForm1 = class(TForm)
Button1: TButton;
Edit1: TEdit;
Label1: TLabel;
Edit2: TEdit;
Edit3: TEdit;
Label2: TLabel;
Label3: TLabel;Button1Click(Sender:
TObject);
{ Private declarations }
{ Public declarations };
Form1: TForm1;
I1, I2: Integer;
{$R *.dfm}(i1,
i2:PInteger):PInteger;:Integer;ESIEAX, dwordptr i1ESI, dwordptriresEAX,
[EAX]ECX, dwordptr i2EAX, [ECX][ESI], EAX@Result, ESIESI;;TForm1.Button1Click(Sender:
TObject);
I1:= StrToInt(Edit1.Text);
I2:= StrToInt(Edit2.Text);
Edit3.Text:= IntToStr(AddTwo(@I1,
@I2)^);
end;.
Скриншот:
Найти сумму элементов в массиве:
Summa of RealsDlg.cpp
#include "stdafx.h"
#include "Summa of
Reals.h"
#include "Summa of
RealsDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CAboutDlg dialog used for App
About: public CDialog
{:();
// Dialog Data{ IDD = IDD_ABOUTBOX
};:void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation:_MESSAGE_MAP()
};
::CAboutDlg() :
CDialog(CAboutDlg::IDD)
{
}::DoDataExchange(CDataExchange*
pDX)
{::DoDataExchange(pDX);
}_MESSAGE_MAP(CAboutDlg,
CDialog)_MESSAGE_MAP()
// CSummaofRealsDlg
dialog::CSummaofRealsDlg(CWnd* pParent /*=NULL*/)
: CDialog(CSummaofRealsDlg::IDD,
pParent)
, s_Array(_T(""))
, f_Summa(0)
{_hIcon =
AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}::DoDataExchange(CDataExchange*
pDX)
{::DoDataExchange(pDX);_Text(pDX,
IDC_EDIT1, s_Array);_Text(pDX, IDC_EDIT2, f_Summa);
}_MESSAGE_MAP(CSummaofRealsDlg,
CDialog)_WM_SYSCOMMAND()_WM_PAINT()_WM_QUERYDRAGICON()
//}}AFX_MSG_MAP_BN_CLICKED(IDC_BUTTON1,
OnBnClickedButton1)_MESSAGE_MAP()
// CSummaofRealsDlg message
handlersCSummaofRealsDlg::OnInitDialog()
{::OnInitDialog();
// Add "About..." menu
item to system menu.
// IDM_ABOUTBOX must be in the
system command range.((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);(IDM_ABOUTBOX
< 0xF000);* pSysMenu = GetSystemMenu(FALSE);(pSysMenu != NULL)
{;.LoadString(IDS_ABOUTBOX);(!strAboutMenu.IsEmpty())
{>AppendMenu(MF_SEPARATOR);>AppendMenu(MF_STRING,
IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The
framework does this automatically
// when the application's main
window is not a dialog(m_hIcon, TRUE);// Set big icon(m_hIcon, FALSE);// Set
small icon
// TODO: Add extra initialization
hereTRUE; // return TRUE unless you set the focus to a control
}::OnSysCommand(UINT nID, LPARAM
lParam)
{((nID& 0xFFF0) == IDM_ABOUTBOX)
{;.DoModal();
}
{::OnSysCommand(nID, lParam);
}
// If you add a minimize button to
your dialog, you will need the code below
// to draw the icon. For MFC
applications using the document/view model,
// this is automatically done for
you by the framework.::OnPaint()
{(IsIconic())
{(this); // device context for
painting(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()),
0);
// Center icon in client rectangle=
GetSystemMetrics(SM_CXICON);= GetSystemMetrics(SM_CYICON);;(&rect);x =
(rect.Width() - cxIcon + 1) / 2;y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon.DrawIcon(x, y,
m_hIcon);
}
{::OnPaint();
}
}
// The system calls this function to
obtain the cursor to display while the user drags
// the minimized
window.CSummaofRealsDlg::OnQueryDragIcon()
{_cast<HCURSOR>(m_hIcon);
}* CSummaofRealsDlg::sumReals(float*
farray, int lf)
{;
_asm {ESI, farrayECX,
lfECX[ESI]:ESI, 4 [ESI]nextEAX, fsum
};
}::OnBnClickedButton1()
{
// TODO: Add your control
notification handler code here[] = {2.4, 5.9, -4.12, 3.12, -8.45};=
sizeof(farray)/4;
//;
//(TRUE);.Empty;(intcnt = 0;
cnt<fsize; cnt++)
{.Format("%.2f",
farray[cnt]);_Array = s_Array + " " + stmp;
};
//_Summa = *sumReals(&farray[0],
fsize);
UpdateData(FALSE);
}
Скриншот: