Перевести VS встроенный ассемблер в GCC встроенный ассемблер
Я нахожу этот код C с встроенным кодом ассемблера:
ReadFromCMOS (unsigned char array [])
{
unsigned char tvalue, index;
for(index = 0; index < 128; index++)
{
_asm
{
cli /* Disable interrupts*/
mov al, index /* Move index address*/
/* since the 0x80 bit of al is not set, NMI is active */
out 0x70,al /* Copy address to CMOS register*/
/* some kind of real delay here is probably best */
in al,0x71 /* Fetch 1 byte to al*/
sti /* Enable interrupts*/
mov tvalue,al
}
array[index] = tvalue;
}
}
WriteTOCMOS(unsigned char array[])
{
unsigned char index;
for(index = 0; index < 128; index++)
{
unsigned char tvalue = array[index];
_asm
{
cli /* Clear interrupts*/
mov al,index /* move index address*/
out 0x70,al /* copy address to CMOS register*/
/* some kind of real delay here is probably best */
mov al,tvalue /* move value to al*/
out 0x71,al /* write 1 byte to CMOS*/
sti /* Enable interrupts*/
}
}
}
Я пытался перевести на встроенный ассемблер GNU, но потерпел неудачу, в основном потому, что встроенный ассемблер GNU грязный, использует архаичный синтаксис AT&T и сложен в использовании.
Код, который дает мне ошибку:
void read_cmos(unsigned char array[])
{
unsigned char tvalue, index;
for (index = 0; index < 128; ++index)
{
/* read from CMOS */
asm ("cli; outb %1, $0x70; inb $0x71, %0; sti" : "=a"(tvalue) : "a"(index));
}
array[index] = tvalue;
}
1 ответ
Попробуйте что-то вроде этого:
/* read from CMOS */
asm ("cli; outb %1, $0x70; inb $0x71, %0; sti" : "=a"(tvalue) : "a"(index));
/* write to CMOS */
unsigned char i = index;
asm volatile ("cli; outb %0, $0x70; movb %1, %%al; outb %%al, $0x71; sti" : "+a"(i) : "rm"(tvalue));
Обратите внимание, что использование дополнительной переменной для tvalue
необязательно. Вы также можете указать
"+a"(array[index])
или же
"a"(array[index])
непосредственно. Важно то, что переданное вами выражение имеет тип байтового размера, поэтому gcc выбирает al
вместо eax
,
Назначение index
в i
необходимо, чтобы позволить al
быть забитым без изменения значения index
, Этот код должен просто работать. В качестве альтернативы второй набор инструкций также можно разделить на две части:
asm volatile ("cli; outb %0, $0x70" :: "a"(index));
asm volatile ("outb %0, %0x71" :: "a"(tvalue));
Это устраняет необходимость в дополнительной переменной и дает большую гибкость компилятору при выборе регистров.
Взгляните на (древний) GCC-inline-assembly HOWTO (ориентированный на i686 Linux, поэтому, вероятно, подходит для вашего использования), внимательно проверьте передачу / ограничения аргументов (они позволяют GCC правильно организовать вызывающий код, например, поместив входы / выходы в используемых регистрах). Документация GCC по встроенной сборке также актуальна, но несколько непрозрачна в моей памяти, гораздо более подробная, подробно описывающая многие другие архитектуры (но, предположительно, более актуальные).
(Извините, я не могу размещать ссылки на моем телефоне. Быстрый поиск должен указать на них в первую очередь.)