Синтаксическая ошибка встроенного ассемблера

Я получал странную ошибку, когда разрабатывал свою операционную систему. Я делал драйвер ввода-вывода, используя outb и inb. Моя функция outb выглядит следующим образом:

static inline void outb(uint16_t port, uint8_t val)
{
    __asm("outb %0, %w1"  //<--Error
        :
        : "a"(val), "Nd"(port));
}

Я получаю эту ошибку в Visual Studio:

C2400: синтаксическая ошибка встроенного ассемблера в «коде операции»; нашел '('

Кто-нибудь знает, почему я получаю эту ошибку? Как исправить эту ошибку? Какие-либо предложения?


person Community    schedule 09.02.2016    source источник
comment
VS? Как в Visual Studio? Код, который вы разместили, не использует синтаксис Microsoft для встроенной сборки. Похоже на что-то предназначенное для GCC.   -  person Michael    schedule 09.02.2016
comment
Действительно, это синтаксис встроенного ассемблера GCC, не Visual Studio. Для Visual Studio я не думаю, что есть хороший способ назначить определенные переменные определенным регистрам, поэтому вы можете просто написать всю функцию на ассемблере, в исходном файле сборки.   -  person user253751    schedule 09.02.2016
comment
Когда я помогал вам ранее, вы использовали ассемблер GNU, а не Microsoft. Как указывает @Michael, синтаксис встроенного Visual C++ в VS сильно отличается от ассемблера GNU. VC++ не поддерживает шаблоны ассемблера, которые являются расширением GCC и недоступны в продуктах MS.   -  person Michael Petch    schedule 09.02.2016


Ответы (1)


Visual Studio VC++ не поддерживает шаблоны ассемблера GNU, доступные в GCC. Поскольку вы определяете port как 16-битное целое число без знака, вам нужно использовать форму OUT , который принимает 16-битный номер порта. Вам нужно поместить 16-битный номер порта в DX. Вы также должны рассматривать имена переменных во встроенной сборке как указатели, поскольку вы используете стандартное соглашение о вызовах CDECL для своих функций. Образец кода:

static inline void outb(uint16_t port, uint8_t val) {
    __asm
    {
        mov dx, port
        mov al, val
        out dx, al
    } 
}

Функцию inb можно выполнить примерно так:

static inline uint8_t inb(uint16_t port)
{
    uint8_t data;
    __asm
    {
        mov dx, port
        in al, dx
        mov data, al
    }
    return data;
}

Это можно упростить, удалив переменную data и сохранив прочитанный символ в переменной port, а затем выполнив return (uint8_t)port;. Так что это также будет работать:

static inline uint8_t inb(uint16_t port)
{
    __asm
    {
        mov dx, port
        in al, dx
        mov byte ptr[port], al   // Need to cast since port is 16-bit variable
    }
    return (uint8_t)port;
}

Дополнительные сведения об использовании встроенной сборки VC++ можно найти в документации Microsoft Developer Network (MSDN) < /а>

person Michael Petch    schedule 09.02.2016
comment
Я бы не назвал это упрощением. - person user253751; 09.02.2016
comment
@immibis Упрощение субъективно, хотя в данном случае мы просто повторно используем уже доступную переменную. Я должен признать, что последний пример страдает от плохой читаемости кода. - person Michael Petch; 11.02.2016