【问题标题】:GCC Inline Assembly 'Nd' constraintGCC 内联汇编“Nd”约束
【发布时间】:2015-12-23 20:46:33
【问题描述】:

我正在用 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" 这样的通用寄存器约束?任何帮助将不胜感激。

【问题讨论】:

  • 您的目标是 16 位代码吗?
  • 我的目标是 32 位代码,因为我使用 GRUB 将我的内核加载到保护模式。

标签: gcc x86 kernel inline-assembly osdev


【解决方案1】:

in 指令(返回一个字节)可以采用立即 8 位值作为端口号,也可以采用 dx 寄存器中指定的端口。有关in 指令的更多信息,请参见instruction reference(英特尔语法)。正在使用的机器约束可以在 GCC docs 中找到。如果你向下滚动到x86 family,你会看到:

d

The d register

没有

Unsigned 8-bit integer constant (for in and out instructions). 

【讨论】:

  • 好的,谢谢。这有很大帮助。但是,我还有最后一个问题,如果 N 约束只允许 0-255 的端口的立即字节,但 d 约束允许整个 dx 寄存器,我为什么不只使用 @987654332 @约束?我的意思是,使用这两种约束有什么好处?
  • @MichaelMorrow 这是 8086/8088 天的延续,当时节省空间通常很重要。如果您使用 8 位立即数(对于 0-255 之间的端口),则不需要额外的指令将其首先移动到 DX(节省空间)。如果您想访问端口 256-65535,您必须将其传递给 DX。您可以在 DX 中指定一个 8 位 (0-255) 端口号,但您必须先将其移动到 DX,从而导致空间上的额外损失。
  • @MichaelMorrow 如果您使用“Nd”作为约束进行优化(-O1、-O2、-O3)编译,如果汇编器模板看到正在传递的值,它将向编译器发出提示可以容纳 8 位并编码较小的版本(无需先移动到 DX)。如果您只使用了“d”,则没有提示编译器可以优化模板中的汇编代码并将使用更长的形式(DX 无论是否需要)。几分钟后,我会用所有这些信息更新我的答案。
猜你喜欢
  • 2011-04-23
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多