gpt4 book ai didi

gcc - 你如何解释gcc对i386的IN、OUT指令的内联汇编约束?

转载 作者:行者123 更新时间:2023-12-04 08:50:42 26 4
gpt4 key购买 nike

据我所知,gcc 内联汇编中使用的约束告诉 gcc 输入和输出变量必须(或必须)去哪里才能生成有效的汇编。正如 Fine Manual 所说,“对操作数放置的限制”。

这是来自 a tutorial 的一个具体的工作示例.

static inline uint8_t inb(uint16_t port)
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "Nd"(port) );
return ret;
}
inb是 AT&T 语法,适用于 i386 IN从 I/O 端口接收一个字节的指令。

以下是该指令的规范,取自 i386 手册。请注意,端口号来自 0x00000xFFFF .
IN AL,imm8  // Input byte from immediate port into AL
IN AX,imm8 // Input word from immediate port into AX
IN EAX,imm8 // Input dword from immediate port into EAX
IN AL,DX // Input byte from port DX into AL
IN AX,DX // Input word from port DX into AX
IN EAX,DX // Input dword from port DX into EAX

给出类似 uint8_t x = inb(0x80); 的语句正确的汇编输出是 inb $0x80,%al .它使用了 IN AL,imm8指令的形式。

现在,假设我只关心 IN AL,imm8表单,收到 uint8_t来自 0x00 之间的端口和 0xFF包括的。这与工作示例之间的唯一区别是 port现在是 uint8_t模板参数(使其有效地成为常量),约束现在是 "N" .
template<uint8_t port>
static inline uint8_t inb()
{
uint8_t ret;
asm volatile ( "inb %1, %0"
: "=a"(ret)
: "N"(port) );
return ret;
}

失败!

我认为“N”约束意味着“对于这条指令,你必须有一个常量无符号 8 位整数”,但显然不是,因为它是一个“不可能的约束”。不是 uint8_t模板参数是一个常量无符号 8 位整数?

如果我用“Nd”替换“N”,我会得到一个不同的错误:
./test.h: Assembler messages:
./test.h:23: Error: operand type mismatch for `in'

在这种情况下,汇编器输出为 inb %dl, %al这显然是无效的。

为什么这只适用于 "Nd"uint16_t而不是 "N"uint8_t ?

编辑:

这是我在 Godbolt.org 上试过的精简版:
#include <cstdint>

template<uint8_t N>
class Port {
public:
uint8_t in() const {
uint8_t data;

asm volatile("inb %[port], %%al"
:
: [port] "N" (N)
: // clobbers
);
return data;
}
};

void func() {
Port<0x7F>().in();
}

有趣的是,这很好用,除非您将 N 更改为 0x80 和 0xFF 之间的任何值。在 clang 上,这会生成“128 超出约束 N 的范围”错误。这会在 gcc 中产生一个更通用的错误。

最佳答案

根据约束的记录方式,您的代码应该按预期工作。

一年多后,这似乎仍然是一个错误。看来编译器正在转换 N从无符号值到有符号值并尝试将其传递到内联汇编约束中。当传递给约束的值不能表示为 8 位有符号值时,这当然会失败。 input constraint "N" 假设允许一个无符号的 8 位值,并且应该接受 0 到 255 (0xff) 之间的任何值:

N

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



有一个类似的 bug report到 GCC 的 bugzilla,标题为“常量约束检查符号扩展无符号常量输入操作数”。

在一个相关线程中,有人建议您可以通过将 (&) 0xff 与常量(即: N & 0xff )进行 AND 运算来解决此问题。我还发现静态类型转换 N到比 uint8_t 更宽的无符号类型也有效:
#include <cstdint>

template<uint8_t N>
class Port {
public:
uint8_t in() const {
uint8_t data;

asm volatile("inb %[port], %0"
: "=a"(data)
: [port] "N" (static_cast<uint16_t>(N))
: // clobbers
);
return data;
}
};

void func() {
Port<0x7f>().in();
Port<0x80>().in();
// Port<0x100>().in(); // Fails as expected since it doesn't fit in a uint8_t
}

要对此进行测试,您可以在 godbolt 上玩它.

关于gcc - 你如何解释gcc对i386的IN、OUT指令的内联汇编约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50769146/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com