Использование отдельных функций на ассемблере
Функция должна удовлетворять соглашениям по вызову для языка С++.
Соглашения по вызову различаются по следующим параметрам:
· Правила формирования внутреннего имени функции;
· Правилами передачи параметров;
· Правилами очистки стека.
При формировании имени возможен регистро – чувствительный или регистро нечувствительный режим, возможно формирование дополнительных символов для обеспечения свойства перегрузки функции.
Для обеспечения возможности использования переменного списка параметров параметры могут записываться в стек, начиная с конца списка, для обеспечения максимальной скорости работы – для передачи параметров используются регистры
Очистку стека может выполнять вызывающая программа или функция.
В табл. 11.4 представлены соглашения по вызову и свойства этих соглашений.
Если файл с программой имеет расширение CPP, то по умолчанию используется режим 1, если файл с расширением С++ - режим 2. Если в программе с расширением СPP необходимо использовать функцию с соглашением С, заголовок этой функции имеет вид:
Extern “C” заголовок;
Если необходимо задать заголовочный файл, который можно использовать в программе на С и СРР, то применяют директивы
#ifdef __cplusplus
extern “C” {
#endif
заголовок 1;
заголовок 2;
…
#ifdef __cplusplus
}
#endif
Пример. Составить вызывающую программу и функции вычисления разности для двух чисел, используя все возможные соглашения по вызову.
Таблица 11.4. Соглашения по вызову, принятые в С++
| №
п/п
|
| Тип соглашения
|
| Как задается
|
| Внутреннее имя функции
|
| Порядок передачи параметров
|
| Очистка стека
|
| Переменный список параметров
|
|
| 1.
|
| Cpp
|
| -
|
| @имя$q[17]…
|
| ¬
|
| Вызывающая программа
|
| Да
|
|
| 2.
|
| С
|
| Extern “C”…
|
| _имя
|
| ¬
|
| Вызывающая программа
|
| Да
|
|
| 3.
|
| Fastcall
|
| Тип __fastcall …
|
| @имя$qqr…
|
| EAX, EDX, ECX
|
| Вызывающая программа
|
| Нет
|
|
| 4.
|
| Stdcall
|
| Тип
__stdcall …
|
| @имя$qqs…
|
| ¬
|
| Функция
|
| Нет
|
|
| 5.
|
| Pascal
|
| Тип
__pascal …
|
| @ИМЯ$Q…
|
| ®
|
| Функция
|
| Нет
|
|
// +ыртэр яЁюуЁрььр
#pragma hdrstop
#include <condefs.h>
#include <stdio.h>
//---------------------------------------------------------------------------
USEASM("std.asm");
USEASM("std1.asm");
USEASM("std2.asm");
USEASM("std3.asm");
USEASM("std4.asm");
//---------------------------------------------------------------------------
#pragma argsused
int __stdcallа substract ( int x, int y, int *z);
intаа substract1 (int x, int y, int *z);
intаа __fastcall substract2 (int x, int y, int *z);
extern "C" intаа substract3 (int x, int y, int *z);
intаа pascal substract4 (int x, int y, int *z);
intаа __fastcall sum (int *x, int y);
int main(int argc, char **argv)
{
ааааа int z;
ааааа substract (3, 2, &z); printf ("%d\n", z);
ааааа substract1 (3, 2, &z); printf ("%d\n", z);
ааааа substract2 (3, 2, &z); printf ("%d\n", z);
ааааа substract3 (3, 2, &z); printf ("%d\n", z);
ааааа substract4 (3, 2, &z); printf ("%d\n", z);
ааааа getchar ();
ааааааа return 0;
}
; stdcall
ideal
p586
model flat
codeseg
procааа @substract1$qiipi
public @substract1$qiipi
argаа a:dword, b:dword, c:dword=s
pushааа ebp
movаааа ebp, esp
pushааа ebx
movаааа eax, [a]
subаааа eax, [b]
movаааа ebx, [c]
movаааа [ebx], eax
popаааа ebx ebp
retаааа
endp
end
;fastcall
ideal
p586
model flat
codeseg
procааа @substract2$qqriipi
publicа @substract2$qqriipi
pushааа esi
movаааа esi, eax
subаааа esi, edx
movаааа [ecx], esi
popаааа esi
retаааа
endp
end
а
;extern C
ideal
p586
model flat
codeseg
procааа _substract3
publicа _substract3
argаа a:dword, b:dword, c:dword=s
pushааа ebp
movаааа ebp, esp
pushааа esi
movаааа esi, [a]
subаааа esi, [b]
movаааа ecx, [c]
movаааа [ecx], esi
popаааа esi ebp
ret
endp
end
; pascal
ideal
p586
model flat
codeseg
proc @SUBSTRACT4$QIIPI
public @SUBSTRACT4$QIIPI
argаа c:dword, b:dword, a:dword=s
pushааа ebp
movаааа ebp, esp
pushааа esi
movаааа esi, [a]
subаааа esi, [b]
movаааа ecx, [c]
movаааа [ecx], esi
popаааа esi ebp
retаааа s
endp
end