Оптимизация для процессоров семейства Pentium: 3. Вызов ассемблерных функций из языка высокого уровня

Дата публикации 22 авг 2002

Оптимизация для процессоров семейства Pentium: 3. Вызов ассемблерных функций из языка высокого уровня — Архив WASM.RU

Вы можете использовать встроенный ассемблер или написать процедуру полностью на ассемблере и вставить ее в свой проект. Если вы выберете последний вариант, рекомендуется, что компилятор умел переводить высокоуровневый код напрямую в ассемблер. Это даст вам гарантию, что вы получите верный метод вызова функции. Большинство компилторов C++ умеют это делать.

Методы вызова функций и манглинг имен могут быть достаточно сложными. Существует много различных соглашений о вызовах функций, и разные марки компиляторов не совместимы друг с другом в этом отношении. Если вы вызываете ассемблерную процедуру из C++, самым логичным и совместимым будет объявляление вашей функции как extern "C" и _cdecl. К имени ассемблерной функции надо прибавить символ подчеркивания и компилировать ее нужно указав чувствительность к регистрам в именах внешних функций и переменных (опция -mx).

Если вам нужно использовать перегружаемые функции, перегружаемые операторы, функции-члены классов и другие расширения C++, тогда вам нужно сначала написать это на C++ и заставить ваш компилятор перевести это в ассемблер, чтобы получить верную информацию о линковке и методе вызова, так как они могут отличаться у разных компиляторов. Если вам нужна ассемблерная функция, соглашение о вызове которой отличается от extern "C" и _cdecl, вам нужно получить ее имя, создаваемое компилятором. Вот пример перегруженной функции вычисления квадратного корня:

Код (Text):
  1.  
  2.   ; int square (int x);
  3.   SQUARE_I PROC NEAR             ; целочисленная функция вычисления квадратного корня
  4.   @square$qi LABEL NEAR          ; имя, создаваемое компилятором Borland
  5.   ?square@@YAHH@Z LABEL NEAR     ; имя, создаваемое компилятором Microsoft
  6.   _square__Fi LABEL NEAR         ; имя, создаваемое компилятором Gnu
  7.   PUBLIC @square$qi, ?square@@YAHH@Z, _square__Fi
  8.           MOV     EAX, [ESP+4]
  9.           IMUL    EAX
  10.           RET
  11.   SQUARE_I ENDP
  12.  
  13.   ; double square (double x);
  14.   SQUARE_D PROC NEAR             ; функция вычисления квадратного корня с двойной точностью
  15.  
  16.   @square$qd LABEL NEAR          ; имя, создаваемое компилятором Borland
  17.   ?square@@YANN@Z LABEL NEAR     ; имя, создаваемое компилятором Microsoft
  18.   _square__Fd LABEL NEAR         ; имя, создаваемое компилятором Gnu
  19.   PUBLIC @square$qd, ?square@@YANN@Z, _square__Fd
  20.           FLD     QWORD PTR [ESP+4]
  21.           FMUL    ST(0), ST(0)
  22.           RET
  23.   SQUARE_D ENDP

Способ передачи параметров зависит от соглашения о вызове функции:

Код (Text):
  1.  
  2.   соглашение          порядок помещения параметров в стек  кто очищает стек
  3.  
  4.   _cdecl              обратный                             вызывающий
  5.   _stdcall            обратный                             процедура
  6.   _fastcall           зависит от компилятора               процедура
  7.   _pascal             прямой                               процедура

Использование регистров в 16-ти битном режиме или Windows, C или C++: 16-ти битное значение возвращается в AX, 32-х битное значение в DX:AX, значение с плавающей запятой в ST(0). Регистры AX, BX, CX, DX, ES и арифметические флаги могут быть изменены процедурой; другие регистры должны быть сохранены и восстановлены. Процедура может полагаться на то, что при вызове другой процедуры значение SI, DI, BP, DS и SS не изменится.

Использование регистров в 32-х битных Windows, C++ и других языках программирования: целочисленное значение возвращается в EAX, значение с плавающей точкой возвращается в ST(0). Регистры EAX, ECX, EDX (но не EBX) могут быть изменены процедурой; все другие регистры должны быть сохранены и восстановлены. Сегментные регистры нельзя изменять даже временно. CS, DS, ES и SS указываеют на плоский сегмент. FS используется операционной системой. GS не используется, но зарезервирован. Флаги могут меняться процедурой, но со следующими ограничениями: флаг направления равен 0 по умолчанию. Его можно изменить временно, но при выходе из процедуры необходимо очистить. Флаг прерывания не может быть очищен. Стековый регистр плавающей запятой пуст при входе в процедуру и должен быть пустым при выходе, если только ST(0) не используется для возвращения значения. Регистры MMX можно изменять, и если это было сделано, их нужно очистить с помощью инструкции EMMS перед возвращением или вызовом любой другой процедуры, которая может использовать регистры плавающей запятой. Все XMM регистры можно свободно изменять. Правила для передачи параметров и возвращения значений через регистры XMM объяснены в интеловском документе AP 589. Процедура может полагаться на неизменность EBX, ESI, EDI, EBP и всех сегментных регистров при вызове другой процедуры. © Агнер Фог, пер. Aquila


0 970
archive

archive
New Member

Регистрация:
27 фев 2017
Публикаций:
532