Ограничение Nd встроенной сборки GCC

Я разрабатываю маленькое игрушечное ядро ​​на C. Я подошел к моменту, когда мне нужно получить пользовательский ввод с клавиатуры. До сих пор я реализовал inb, используя следующий код:

static inline uint8_t inb(uint16_t port) {
     uint8_t ret;
     asm volatile("inb %1, %0" : "=a"(ret) : "Nd"(port));
     return ret;
}

Я знаю, что ограничение "=a" означает, что al/ax/eax будет скопировано в ret в качестве вывода, но я все еще не понимаю ограничение "Nd". Может ли кто-нибудь дать некоторое представление о том, почему это ограничение необходимо? Или почему я не могу просто использовать ограничение регистра общего назначения, такое как "r" или "b"? Любая помощь будет оценена.


person Michael Morrow    schedule 25.09.2015    source источник
comment
Вы ориентируетесь на 16-битный код?   -  person Michael Petch    schedule 26.09.2015
comment
Я нацелен на 32-битный код, так как использую GRUB для загрузки ядра в защищенный режим.   -  person Michael Morrow    schedule 26.09.2015


Ответы (1)


Инструкция in (возвращающая байт) может принимать либо непосредственное 8-битное значение в качестве номера порта, либо порт, указанный в регистре dx. Дополнительную информацию об инструкции in можно найти в справочнике по инструкциям (синтаксис Intel). Используемые машинные ограничения можно найти в документации GCC. Если вы прокрутите вниз до x86 family, вы увидите:

d

The d register

N

Unsigned 8-bit integer constant (for in and out instructions). 
person Michael Petch    schedule 25.09.2015
comment
Хорошо спасибо. Это очень помогло. Однако у меня есть еще один последний вопрос: если ограничение N разрешает только непосредственный байт для портов от 0 до 255, а ограничение d разрешает весь регистр dx, почему бы мне не использовать только ограничение d? Я имею в виду, каковы преимущества использования обоих ограничений? - person Michael Morrow; 26.09.2015
comment
@MichaelMorrow Это отмена времен 8086/8088, когда экономия места часто была важна. Если вы используете 8-битный режим сразу (для порта от 0 до 255), вам не нужна дополнительная инструкция, чтобы сначала переместить его на DX (экономия места). Если вы хотели получить доступ к порту 256-65535, вам нужно было передать его в DX. Вы можете указать 8-битный (0-255) номер порта в DX, но вы понесете дополнительный штраф в пространстве, поскольку сначала вам придется переместить его на DX. - person Michael Petch; 26.09.2015
comment
@MichaelMorrow Если вы компилируете с оптимизацией (-O1, -O2, -O3) с использованием Nd в качестве ограничения, шаблон ассемблера даст подсказку компилятору, если он увидит, что передаваемое значение может уместиться в 8 бит и закодировать меньшую версию (не переходя сначала к DX). Если вы только что использовали d, то нет никакого намека на то, что компилятор может оптимизировать код ассемблера в шаблоне и будет использовать более длинную форму (с DX, требуется или нет). Через несколько минут я дополню свой ответ всей этой информацией. - person Michael Petch; 26.09.2015