Каково различие между этими двумя формами встроенного ассемблера в C?

Фон: для меня определили задачу с записью программы сбора данных для Unitech HT630, который выполняет собственную операционную систему DOS, которая может выполнить исполняемые файлы, скомпилированные для 16-разрядного MS DOS, хотя с некоторыми ограничениями. Я использую Цифровой Марс компилятор C/C++, который, кажется, работает очень хорошо.

Для некоторых вещей я могу использовать стандартные библиотеки для C, но другие вещи как привлечение экрана единицы требуют ассемблерного кода. Примеры блока, данные в документации устройства, отличаются от того, как мне преподавали использовать код встроенного ассемблерного кода в C/C++. Для ссылки, BYTE в примерах ниже имеет тип unsigned char.

Образец примера кода мне дали:

#include 

/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
  if(status > 1 || x > 63 || y > 127) {
    /* out of range, return */
    return;
  }
  /* good data, set the pixel */
  union REGS regs;
  regs.h.ah = 0x41;
  regs.h.al = status;
  regs.h.dh = x;
  regs.h.dl = y;
  int86(0x10, ®s, ®s);
}

Как мне всегда преподавали использовать встроенный ассемблерный код:

/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
  if(status > 1 || x > 63 || y > 127) {
    /* out of range, return */
    return;
  }
  /* good data, set the pixel */
  asm {
    mov AH, 41H
    mov AL, status
    mov DH, x
    mov DL, y
    int 10H
  }
}

Обе формы, кажется, работают, я не встретился с проблемой ни с одним подходом на данный момент. Одну форму считают лучше, чем другой для программирования DOS? Делает int86 указатель на функцию что-то для меня, что я не обрабатываю меня в своем собственном ассемблерном коде во втором примере?

Заранее спасибо за любую справку.

7
задан Heather M 18 January 2010 в 15:22
поделиться

6 ответов

При использовании функции int86 вызов функции int86 , который является вызовом библиотеки времени выполнения C, который устанавливает регистры и выдает DOS int int . Оба метода действительно одинаковы с одним исключением, когда вы используете встроенный ассемблер, код фактически встроен в объектный код при компиляции и связанном.

Встроенный сборник будет считаться быстрее, так как у вас нет накладных расходов, участвующих в вызове библиотеки времени выполнения C, чтобы вызвать прерывание DOS для вас. Внутри на вас, чтобы обеспечить достаточно места для стека при использовании встроенной сборки, тогда как библиотека времени выполнения C приходится ухаживать за выделением пространства стека при настройке регистров перед вызовом функции INT86 .

Int86 INT86 - это способ облегчить призыв к прерываниям DOS. Это было чрезвычайно популярно среди старого собора компиляторов Borland Turbo Compilers и Microsoft, я говорю о старых компиляторах, прежде чем выиграл 3.1.

Говоря о прерывании 0x10, который отвечает за выходной выход, если я правильно помню, в то время, некоторые BIOS уничтожили реестр и обходной путь должен был сделать это:

__asm{
   push bp;
}
/* set up the registers */
int86(0x10, &regs, &regs);
__asm{
   pop bp;
}

вы Можно узнать обширные функции BIOS на списке прерываний Ральфа Брауна здесь . Также HelpPC V2.1 может также помочь, найден здесь .

9
ответ дан 6 December 2019 в 19:36
поделиться

Первая форма более читаема, которая также имеет значение для чего-то; -)

Если вы хотите знать, если INT86 делает что-то за спиной, просто соберите свою программу и осмотрите сгенерированную сборку код

1
ответ дан 6 December 2019 в 19:36
поделиться

Вызовом int86 ваш код остается на C. В любом случае, он пишет пиксел, делая системное прерывание.

Если у вас есть лот пикселей для записи, и вы начинаете серьезно бить по проблемам со скоростью, то, возможно, есть более прямой (и гораздо менее безопасный, но, возможно, стоящий) способ записи непосредственно в память пикселей.

1
ответ дан 6 December 2019 в 19:36
поделиться

Оба фрагмента кода достигают одного и того же. Большим преимуществом первого является то, что есть некоторая вероятность того, что вы все равно сможете его использовать при переключении компиляторов. И то, что вы не растопчите регистр, который использовался генератором кода компилятора 'C' для других целей. Кое-что, о чём вы определённо забыли позаботиться в своём фрагменте asm.

1
ответ дан 6 December 2019 в 19:36
поделиться

Вам следует обратиться к руководству компилятора, чтобы узнать, кто отвечает за восстановление значений регистров после раздела сборки inline. Так как ваши переменные присваиваются регистрам, непреднамеренное изменение значений может привести к труднодостижимым ошибкам. int86(0x10, ®s, ®s); сохраняет регистры и восстанавливает их после выполнения программного прерывания.

Некоторые компиляторы принимают инструкции по определению списка помех (регистров, которые должны быть сохранены и восстановлены). Обычно секция ассемблера должна сохранять регистры и флаги, которые будут изменены с помощью push, и восстанавливать их с помощью pop, либо компилятором, либо самим собой. Поэтому первый пример должен быть предпочтительнее.

1
ответ дан 6 December 2019 в 19:36
поделиться

Это не встроенная сборка, это C. Очень низкоуровневая C, использующая функцию для вызова прерывания, но все же C.

Эта страница содержит некоторую документацию (для компилятора DJGPP ваша может работать по-другому), включая структуру, используемую для представления регистров. Она также отмечает:

Обратите внимание, что в отличие от __dpmi_int работа, запросы, которые проходят int86 и аналогичные функции специально обработанный для их изготовления подходящий для использования в реальном режиме прерывания работы в защищённом режиме программы. Например, если конкретный рутина принимает указатель в BX, int86 ожидает, что вы установите (защищенный режим) указатель в EBX. Таким образом, int86 должен иметь конкретную поддержку для каждого прерывание и функция, которую вы вызываете Путь. В настоящее время он поддерживает только подмножество всех доступных прерываний и функции [...]

0
ответ дан 6 December 2019 в 19:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: