GNU汇编语法
我在写一个内联汇编代码来读取实时时钟。我正在加载寄存器编号(4)以读取到'dl'并将其加载到端口0x70。我正在尝试将这个寄存器值(4)读入al。欲了解更多信息 - RTCGNU汇编语法
asm(
"mov $4, %%dl;"
"out 0x70, %%dl;"
"in %%al, 0x71;"
:
:
:"%al","%dl"
);
我正在上编译包含该代码的C文件下面的错误消息。
Assembler messages:
Error: operand size mismatch for 'out'
Error: operand size mismatch for `in'
汇编器版本:使用BFD版(GNU Binutils的Ubuntu的)GNU汇编版本2.26.1下(x86_64-Linux的GNU)2.26.1
是否有人可以指出的问题?
存在一些问题。首先,in
和out
都只能在A寄存器(al
,ax
,eax
,rax
)上运行。其次,操作数顺序是错误的,第三,立即数必须以AT & T语法中的$
作为前缀。在普通的装配,你的代码应该是这样的:
mov $4,%al
out %al,$0x70
in $0x71,%al
所以,你纠正装配将
asm(
"movb $4, %%al;"
"outb %%al, $0x70;"
"inb $0x71, %%al;"
:
:
:"%al"
);
请注意,我已经加入明确的大小后缀,以帮助铛组装此代码。我建议你进一步改变该代码使用正确的扩展内联汇编:
unsigned char result;
volatile asm("outb %1,$0x70; inb $0x71, %0" : "=a"(result) : "a"((char)4));
这可能使GCC产生稍微好一点的代码。例如,它允许gcc内联这些代码。此外,你可以考虑使用来自<sys/io.h>
的inb()
和outb()
宏来完全避免内联汇编。这通常是一件很好的事情。
谢谢你的详细解答。你能指点我一个关于内联汇编的AT&T语法的综合指南,以便避免这种语法错误吗? – SilentMonk
@SilentMonk阅读GNU汇编程序的手册。 – fuz
您还应该获得一个很好的指令集引用,它会告诉您没有dl作为源的out指令。我使用英特尔手册(https://software.intel.com/zh-cn/articles/intel-sdm)。 – prl
根据猜测,错误信息是由于在常量前没有'$'。也就是说,如果你想让你的asm输出一个值,你需要有一个输出参数(在第一个冒号后面)。如果在运行Ubuntu时可以使用'in'或'out',我会感到很惊讶。在阅读RTC之前,你不应该“cli”吗?如果你正在构建16位代码,我不确定使用64位编译器是否可行。如果你想在启动时读取RTC,那么[this](https://*.com/q/46074535/2189500)。 –
AT&T语法通常在右侧有目的地。我希望对于IN和OUT指令也是如此。 IN 0x71,%% al'? –
@DavidWohlferd在给予自己使用'iopl()'或'ioperm()'系统调用的权利后,你可以使用'in'和'out'。 – fuz