2013-06-03 100 views
1

内联汇编中的输出寄存器必须用“=”约束声明,意思是“只写”[1]。这意味着什么 - 它是否真的被禁止在大会内部读取和修改它们?例如,请考虑以下代码:在avr-gcc内联汇编中使用输出寄存器有哪些限制?

uint8_t one() 
{ 
    uint8_t res; 
    asm("ldi %[res],0\n" 
     "inc %[res]\n" 
     : [res] "=r" (res) 
    ); 
    return res; 
} 

程序集将输出寄存器设置为0,然后递增它。这是否打破了“只写”约束?

UPDATE

我看到在我的内联汇编休息时,我把它改为直接在输出寄存器的工作,而不是使用R16的计算,最后mov'ing R16到输出问题寄存器。代码在这里:http://ideone.com/JTpYma。它将结果打印到串行,你只需要定义F_CPU和BAUD。只有使用gcc-4.8.0而不使用gcc-4.7.2时才会出现该问题。

[1] http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

回答

2

编译器不关心你是否读它与否,它只是不会把变量的初始值到寄存器。你举的例子是完全合法的,但人们往往错误地期望得到源于此代码2

uint8_t one() 
{ 
    uint8_t res = 1; 
    asm("inc %[res]\n" 
     : [res] "=r" (res) 
    ); 
    return res; 
} 

因为它只是一个输出的制约,中res初始值不能保证被加载到寄存器。事实上,假设asm块会覆盖它,甚至可以优化初始化器。上面的代码是由我的版本AVR-GCC编译这样:

inc r24 
ret 

正如你所看到的,确实编译取出装载1res,因此进入r24从而产生不确定的结果。


更新

与问题的更新程序的问题是,它也有一个输入寄存器操作数。默认情况下,编译器假定在分配输出之前所有输入都被消耗,因此分配重叠寄存器是安全的。你的例子显然不是这种情况。您应该使用“早期披肩”修饰符(&)作为输出。这是手动不得不说有关:

&手段(在一个特定的替代物),这操作数是一个 earlyclobber操作数,之前的指令是 使用输入操作数完成被修饰。因此,该操作数可能不在 的某个寄存器中,该寄存器用作输入操作数或任何内存地址的一部分。

没有人说GCC内联汇编很简单:d

+0

你可能是错在这里,看到我的编辑。或者它只是一个编译器错误。 –

+0

编辑答案也是。 – Jester

+0

确实修复了它,谢谢! –

相关问题