Использование отдельных функций на ассемблере
Функция должна удовлетворять соглашениям по вызову для языка С++.
Соглашения по вызову различаются по следующим параметрам:
· Правила формирования внутреннего имени функции;
· Правилами передачи параметров;
· Правилами очистки стека.
При формировании имени возможен регистро – чувствительный или регистро нечувствительный режим, возможно формирование дополнительных символов для обеспечения свойства перегрузки функции.
Для обеспечения возможности использования переменного списка параметров параметры могут записываться в стек, начиная с конца списка, для обеспечения максимальной скорости работы – для передачи параметров используются регистры
Очистку стека может выполнять вызывающая программа или функция.
В табл. 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