2017-09-10 253 views
0

我在写一个内联汇编代码来读取实时时钟。我正在加载寄存器编号(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

是否有人可以指出的问题?

+3

根据猜测,错误信息是由于在常量前没有'$'。也就是说,如果你想让你的asm输出一个值,你需要有一个输出参数(在第一个冒号后面)。如果在运行Ubuntu时可以使用'in'或'out',我会感到很惊讶。在阅读RTC之前,你不应该“cli”吗?如果你正在构建16位代码,我不确定使用64位编译器是否可行。如果你想在启动时读取RTC,那么[this](https://stackoverflow.com/q/46074535/2189500)。 –

+2

AT&T语法通常在右侧有目的地。我希望对于IN和OUT指令也是如此。 IN 0x71,%% al'? –

+0

@DavidWohlferd在给予自己使用'iopl()'或'ioperm()'系统调用的权利后,你可以使用'in'和'out'。 – fuz

回答

4

存在一些问题。首先,inout都只能在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()宏来完全避免内联汇编。这通常是一件很好的事情。

+0

谢谢你的详细解答。你能指点我一个关于内联汇编的AT&T语法的综合指南,以便避免这种语法错误吗? – SilentMonk

+0

@SilentMonk阅读GNU汇编程序的手册。 – fuz

+0

您还应该获得一个很好的指令集引用,它会告诉您没有dl作为源的out指令。我使用英特尔手册(https://software.intel.com/zh-cn/articles/intel-sdm)。 – prl