【发布时间】:2021-11-15 21:06:25
【问题描述】:
我不确定我是否不小心修改了代码,但这里是(我是内联汇编的初学者,但很习惯在不同的文件中汇编):-
void out8(uint16 port, uint8 data) {asm volatile("outb %0, %1" : "dN"(port) : "a"(data));}
void out16(uint16 port, uint16 data) {asm volatile("outw %0, %1" : "dN"(port) : "a"(data));}
void out32(uint16 port, uint32 data) {asm volatile("outl %%eax, %%dx" : "dN"(port) : "a"(data));}
以前它没有给出错误,但现在它是。但任何人都可以更正这段代码吗?还有,告诉我冒号分隔值的依据是什么,冒号分隔区域中的“dN”和“a”, 内联汇编中的“%0”和“%1”,为什么“a”和“dN”旁边的括号中的那些变量“port”和“data”以及“%[ reg]" 和 "%%[reg]" 以便我以后得到它们时可以解决这些问题。 (tl;du(u 代表理解)内联扩展汇编的手册页是日语(你知道我的意思,对吗?))
[已解决]
使用过:-
void out(uint16 port, uint8 data) {asm volatile("outb %1, %0" :: "dN"(port), "a"(data));}
void out(uint16 port, uint16 data) {asm volatile("outw %1, %0" : : "dN"(port), "a"(data));}
// Warning, this one's still unsafe, even though it compiles
void out(uint16 port, uint32 data) {asm volatile("outl %%eax, %%dx" : : "dN"(port), "a"(data));}
(对未来读者的警告:outl 仍有错误,请参阅答案。)
【问题讨论】:
-
在询问涉及构建错误的问题时,总是包含您遇到的实际错误。最好是一个合适的minimal reproducible example 也向我们展示。
-
你读过多少the GCC documentation? inline assembly documentation 关于这个问题的哪些部分你不明白?
-
显然,请阅读语法手册。 gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html。由于将端口号作为输出(在第一个
:之后,而不是第二个),它们都被破坏了。另外,你单独打破了out32。"dN"约束允许编译器选择 DX 或立即数,但您不引用%0第一个操作数,而是始终假设它将选择 DX。因此,为out32(12, 0x1234)内联的优化构建将not 将端口号放入DX,但模板中没有%0,$12不会被替换到编译器的任何地方-生成的汇编。 -
另请参阅stackoverflow.com/questions/tagged/inline-assembly 以获取指向官方文档以外的指南的链接。如果您对
out有两个“输入”这一事实感到困惑,请将其视为存储指令。两条数据来自 CPU(数据和地址),从而存储到内存中。与 load 或in不同,其中 load 指令写入寄存器,编译器需要知道结果放在哪里。 -
正如我所说,GNU C 内联汇编使编写可编译但不能通过约束向编译器/优化器准确描述模板的代码变得非常容易。因此,它会因周围代码和编译器选项的某些组合而中断。 “它编译”是必要的,但 远 不足以使内联汇编正确。
标签: c++ assembly gcc inline-assembly