【发布时间】:2021-03-04 19:50:32
【问题描述】:
如何在 GNU 汇编器中使用 x86 ins 指令?指令参考建议使用语法INS m8/16/32, DX,例如m16(我假设)是任何 16 位通用寄存器,其唯一目的是表示是否应该读取字节/字/双字,对吧?
现在,很遗憾,as 拒绝 ins %ax,%dx 和 Error: operand type mismatch for 'ins',这是为什么呢?
作为记录,我知道我可以简单地使用 insb 等,但我通过 C++ 程序中的内联汇编调用此指令,并且要读取的输入的大小取决于模板参数(和字符串处理在编译时不是很实用)。
编辑:这是我现在所拥有的,供参考(我不太喜欢宏)
#define INS(T) \
__asm__ __volatile__("repne \n\t" \
"ins" T \
: "=D" (dest), "=c" (count) \
: "d" (port), "0" (dest), "1" (count) \
: "memory", "cc")
template<typename T>
void ins(uint16_t port, uint32_t dest, uint32_t count);
template<>
void ins<uint8_t>(uint16_t port, uint32_t dest, uint32_t count)
{ INS("b"); }
template<>
void ins<uint16_t>(uint16_t port, uint32_t dest, uint32_t count)
{ INS("w"); }
template<>
void ins<uint32_t>(uint16_t port, uint32_t dest, uint32_t count)
{ INS("l"); }
【问题讨论】:
-
它应该是一个 memory 引用,而不是一个寄存器。英特尔语法中的想法是,您可以编写
ins dword ptr [rdi], dx用于 32 位读取(又名insd),ins word ptr [rdi], dx用于 16 位读取insw等。您甚至可以编写ins dword ptr [foo], dx和进行 32 位读取,但无论如何数据都会写入[rdi]。尽管如此,AT&T 汇编语法根本不支持这一点,指定大小的唯一方法是使用操作数大小后缀。 -
您可能能够通过将编译器切换为使用 Intel 语法来破解它,但我认为这会很痛苦。我会尝试弄清楚如何在编译时选择正确的
insb / insw / insl之一。我不明白你为什么需要字符串处理;只需编写所有三个并使用模板专业化或switch或其他任何东西来执行正确的。 -
(别忘了小心你的操作数、约束和破坏;该指令修改了
rdi。你知道你不能在非特权代码中执行这些指令,除非你已经做过诸如iopl()之类的事情?我假设您正在编写内核或裸机嵌入式代码,只是其中任何一个都是C ++有点不寻常。) -
@NateEldredge:好吧,我明白了。我猜我将不得不处理一些代码重复。我想我正确地处理了约束,我会检查编译器的输出,是的,我正在编写一个内核。
-
其实我觉得可以用操作数修饰符来完成。写一个答案...
标签: x86 g++ inline-assembly att ioports