Взаимосвязь языков C и ассемблера

Раздел 1: Регистры и параметры

                         1.1 Использование регистров

      В создаваемых ассемблерных программах можно использовать все  регистры
процессора. Но чтобы предотвратить путаницу с функциями С и С++,  необходимо
восстанавливать bp, cs, sp и ss, которые  они  имели  до  запуска  созданной
подпрограммы. Тогда можно быть совершенно уверенным, что обращение к  другим
функциям не изменит эти регистры. Также нельзя забывать,  что  С  использует
регистры si и di  для  регистровых  переменных,  поэтому  при  использовании
встроенного ассемблера замедляется общая работа программы.
      К регистрам ax, bx, cx, dx и es можно обращаться свободно и  не  нужно
резервировать их значения до окончания подпрограммы. Эта свобода касается  и
других функций, поэтому надо помнить,  что  эти  регистры  изменяться,  если
вызываются функции С и С++ из ассемблерных подпрограмм.

                      1.2 Ассемблерные операторы Inline

      Ассемблерные  операторы  inline  начинаются  словом  asm,  за  которым
следует  инструкция  и  ее  операнды.   Например,   чтобы   синхронизировать
программу с внешним сигналом прерывания, можно написать:
      /* ожидание прерывания*/
      asm sti
      asm hlt
      printf(“Прерывание получено\n”)
      Когда ранние версии  Turbo  C  компилируют  программу  со  встроенными
командами  asm,  компилятор  сперва  создает  ассемблерный  текст  для  всей
программы,  вставляя  в  текст  наши  ассемблерные   инструкции   вместе   с
откомпилированным  кодом  для  остальных  операторов  С.  Затем   компилятор
вызывает  Turbo   Assembler   и   Linker   (компоновщик),   чтобы   провести
ассемблирование  и  подключить  программу  к  конечному  файлу  кода.  Более
поздние версии Turbo и Borland C++ могут  компилировать  операторы  asm  без
вызова TASM. Полный синтаксис asm:
      asm[метка] мнемоника/директива операнды [;] [/*С комментарий*/]
      Точки с запятыми в конце строк  asm  и  комментарии  С,  расположенные
между /*и*/ удаляются из текста перед  ассемблированием,  поэтому  их  можно
опускать в тексте программы.



            1.3 Размещение данных и операторов в тексте программы

      Каждая строка текста программы С и С++  находится  либо  внутри,  либо
снаружи функции, и операторы asm могут вставляться как  в  одном,  так  и  в
другом  месте.  Конкретное  положение  оператора  asm  влияет  на  то,  куда
ассемблируется код или  директива.  Если  оператор  asm  появляется  снаружи
функции, то он  ассемблируется  в  сегмент  данных  программы,  если  внутри
функции - в кодовый сегмент. Обычно,  чтобы  создать  переменные,  операторы
asm вставляются снаружи функций; для  создания  кода  их  следует  вставлять
внутрь функций. Например:
      asm count db ?
      int main()
      {
       asm shl [count], 1/*умножение count на 4*/
       asm shl [count], 1
       return 0;
      }
        Переменная   count   объявляется   в   сегменте   данных   программы
(относительно ds). Операторы  внутри  функции  main  умножают  count  на  4,
используя  вместо  mul  быстрые  инструкции  сдвига  shl.   Если   объявлять
переменные внутри функции, данные ассемблируются в кодовый  сегмент,  требуя
особого обхождения:
      int main()
      {
       asm jmp OverThere
       asm count db ?
      OverThere:
       asm shl [count], 1 /* умножение count на 4*/
       asm shl [count], 1
       return 0;
      }
      Поскольку  теперь  переменная  count  находится  в  кодовом  сегменте,
требуется инструкция jmp,  чтобы  избежать  случайного  восприятия  значения
count в качестве машинного кода и его исполнения.