ARM内联汇编的GCC错误信息:期望ARM寄存器

3

下面是我用C和内联汇编编写的一段代码,用于将数组blk中的一些short值加载到ARM R寄存器中。

...
short *blk; 
... //blk memory allocation and initialization
short tmp0, tmp1, tmp2;
asm volatile (
"ldrh %[tmp0], [%0]\n\t"
"ldrh %[tmp1], [%1]\n\t"
"ldrh %[tmp2], [%2]\n\t"
: [tmp0] "=r" (tmp0), [tmp1] "=r" (tmp1), [tmp2] "=r" (tmp2)
: "m" (blk[0])  , "m" (blk[8]), "m" (blk[8*2])
: 
);

我从arm gcc 4.6收到了这个错误信息。

/tmp/ccDEBLCN.s:266: Error: ARM register expected -- `ldrh r3,[[r5,#0]]'

GCC抱怨ldrh %[tmp2], [%2]这行有问题,但我不知道是什么原因。我看了一下LDRH指令,感觉我的指令模板没错。

Load memory halfword [15:0] from register address + 5-bit immediate offset
LDRH <Rd>, [<Rn>, #<immed_5> * 2]

顺便提一下,我正在使用以下命令来编译这个代码:

arm-none-linux-gnueabi-gcc -O2 -march=armv7-a -mthumb 

你尝试过将“=r”更改为“r”吗?这是我正在使用的语法。 - BitBank
应该是 "=r",因为 tmp 是输出。无论如何,如果我将其更改为 "r",就会出现此错误。193:3: error: output operand constraint lacks '=' 193:3: error: invalid lvalue in asm output 0 - aminfar
有什么想法吗?我还没有找到解决这个问题的方法。 - aminfar
如果代码只是你展示的那样,那么编译器就会有理由抱怨你将数据加载到寄存器中却没有使用它。ARM不支持内存到内存的操作,因此您需要将数据加载到寄存器中,然后将数据再存回内存中。 - BitBank
不,我从代码中删除了许多细节。但我不明白你的评论。你是从哪条信息中得出我没有使用数据?无论如何,即使我没有使用数据,这也应该是一个警告,而很明显我没有收到来自编译器的任何警告消息。此外,为什么要说我在进行 mem 到 mem 操作?LDR 明确地从地址(这里是 blk,而 "m" 表示允许内存操作数,带有机器支持的任何类型的地址)加载到寄存器(这里是 tmp,而 "r" 表示 ARM 核心寄存器)。最后,在这段代码中,我没有存储任何数据。很抱歉我不理解你的意思。 - aminfar
错误可能是虚假的。GCC在内置函数和内联汇编语言方面有很多错误。它还尝试消除“死存储”。即设置了但从未使用的变量。在上面的代码中,您将3个值加载到寄存器中,但没有变量。ARM是一种装载/存储体系结构-每个指令只能装载或存储数据,不能两者兼备。如果编译器接受您编写的代码,它将不会执行任何操作。它可能会将值加载到临时寄存器中,但这些值将立即被下一个指令覆盖。 - BitBank
2个回答

2
asm (
"ldrh %[tmp0], %[ref0]\n\t"
"ldrh %[tmp1], %[ref1]\n\t"
"ldrh %[tmp2], %[ref2]\n\t"
: [tmp0] "=&r" (tmp0), [tmp1] "=&r" (tmp1), [tmp2] "=r" (tmp2)
: [ref0] "m" (blk[0])  , [ref1] "m" (blk[8]), [ref2] "m" (blk[8*2])
: 
);

1

看起来编译器可能会抱怨你的代码实际上什么也没做。这是你真正想做的吗?

...
short *blk; 
... //blk memory allocation and initialization
short tmp0, tmp1, tmp2;
asm volatile (
"ldrh r0,[%[BLK]]\n\t"
"ldrh r1,[%[BLK], #8]\n\t"
"ldrh r2,[%[BLK], #16]\n\t"
"strh r0,[%tmp0] \n\t"
"strh r1,[%tmp1] \n\t"
"strh r2,[%tmp2] \n\t"
: [tmp0] "r" (tmp0), [tmp1] "r" (tmp1), [tmp2] "r" (tmp2), [BLK] "r" (blk)
: "r0", "r1", "r2"
: 
);

是的,有点类似。您可以使用ro、r1、r2作为临时寄存器。但我尝试直接从内存(这里是blk数组)加载到tmp0、tmp1和tmp2中(tmp0、tmp1和tmp2本身存储在r寄存器中)。这里给出的另一个答案直接将加载到tmp变量中。感谢您的帮助。 - aminfar
让我重新表达我的意思。我想从内存(这里是blk)加载到核心寄存器(这里是R寄存器),并且我希望在我的C代码中将这些寄存器称为tmp0,tmp1,tmp2变量。 - aminfar
3
我总是假设GCC会做错事情,通常我都是正确的。我认为你要求GCC在内联汇编中为本地变量分配寄存器并使其正常工作,这是要求太多了。内联汇编是一种特殊情况(例如欺骗),GCC似乎没有像处理周围C代码那样对待它。从我的经验来看,您需要让汇编代码完成所有需要完成的工作,并假定它与C代码不同,唯一的例外是您可以读取C变量,但编译器认为你仍然没有访问这些变量,除非C语言也使用它们。 - BitBank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接