
Вопрос 20
Вызов функции С из ассемблера.
Нас интересуют 3 вопроса: как передать аргументы в процедуру на ассемблере, как к ним обратиться в процедуре на ассемблере и как возвратить результат? В начале отметим, что всегда нужно сохранять содержимое регистров BP, SP, CS, DS, SS. Это делается перед вызовом процедуры. Остальные регистры нужно сохранять по необходимости
Rомпиляторы языков C/C++ разрабатываются множеством фирм — в отличие от Pascal, компилятор для которого выпускает практически одна фирма Borland. Это обстоятельство, на мой взгляд, — основная причина сложности связи С—ассемблер, так как каждая фирма реализует ее по-своему (хотя суть и остается практически неизменной). Поэтому, как мне кажется, нет смысла рассматривать множество частных случаев.
Как правило, компиляторы позволяют связывать модули на C/C++ и ассемблере с использованием средств командной строки. Так как этот процесс довольно хорошо стандартизован, есть смысл его рассмотреть. В качестве примера выберем компилятор С++ 5.0 фирмы Inprise. Типовая последовательность шагов выглядит примерно так:
Составить текст программы на С++, объявить процедуру asmproc внешней:
extern void asmproc(char ch, unsigned x, unsigned y, unsigned kol);
Выполнить трансляцию модуля С++ и получить объектный модуль:
Ьсс -с prgi5_l9.cpp
Параметр -с здесь означает, что выполняется только компиляция исходного файла, загрузочный модуль не создается
Составить текст процедуры на ассемблере в которой объявить процедуру asmproc общедоступной с помощью директивы PUBLIC. Заметьте, что идентификатору asmproc предшествует символ подчеркивания (_asmproc). Компилятор C/C++ добавляет знак подчеркивания ко всем глобальным идентификаторам. Более того, некоторые компиляторы (VC++) могут кроме символа подчеркивания добавлять в конце исходного идентификатора комбинацию символов @nn, где nn означает количество байтов, занимаемых аргументами процедуры в стеке
Выполнить трансляцию программы на ассемблере:
tasm prgl5_20,,,
Выполнить объединение объектных модулей:
bcc -ms prgl5_19.obj prgl5_20.obj
Как возвратить результат в программу на С из процедуры на ассемблере? Для этого существуют стандартные соглашения (табл. 15.3). Перед возвратом управления в программу на С в программе на ассемблере необходимо поместить результат или сформировать указатель в заданных регистрах.
Тип возвращаемого значения в С++ |
Место записи результата |
Unsingned char |
AX |
Char |
AX |
Emum |
AX |
Unsigned short |
AX |
Short |
AX |
Unsingned int |
AX |
Int |
AX |
Unsingned long |
DX-AX |
Long |
DX-AX |
Указатель near |
AX |
Указатель far |
DX-AX |
Обратите внимание на то, что листинг 15.19 содержит текст исходного файла срасширением .срр, а листинг 15.21 — с расширением .с. Соответственно, сами исходные тексты в части организации межмодульного взаимодействия также различаются.
Листинг 15.19. Вызывающий модуль на С++
//prgl5_19.cpp
#include <stdio.h>
#include <conio.h>
extern "C" void asmproc(char ch, unsigned x, unsigned у.unsigned kol);
void main (void)
{
clrscrO;
asmproc('a4,2,3,5);
asmprocCs' , 9. 2, 7);
}
Листинг 15.21. Вызывающий модуль на C/C++
/ * р г g15_21.с*/
#include <stdio.h>
extern int sum_asm(int mass1v[],1nt count);
main()
{
int mas[5] = {1,2,3,4,5};
int len=5; int sum;
sum=sum_asm(mas,len);
printf ("%d\n" .sum) ;
return(0) ;
}