2014-11-14 64 views
0

我正在为AVR编写一个RPC库,并且需要将函数地址传递给某些内联汇编程序代码,并从汇编程序代码中调用该函数。但是,当我尝试直接调用该函数时,汇编程序抱怨。传递给gcc内联汇编程序的调用const函数地址(avr-gcc)

这个小例子说明TEST.CPP问题(在我传递ARGS的实际情况和功能模板类的静态成员的一个实例):

void bar() { 
    return; 
} 

void foo() { 
    asm volatile (
     "call %0" "\n" 
     : 
     : "p" (bar) 
    ); 
} 

avr-gcc -S test.cpp -o test.S -mmcu=atmega328p编译工作正常但是当我尝试组装avr-gcc -c test.S -o test.o -mmcu=atmega328p AVR-的抱怨:

test.c: Assembler messages: 
test.c:38: Error: garbage at end of line 

我不知道为什么它写道:“test.c的”,它指的是该文件是test.S,其中包含该线路38上:

call gs(_Z3barv) 

我试图在参数设置为内联汇编,我能找到here所有甚至远程明智的约束,但是没有那些我试过的工作。

我想象如果gs()部分被删除,一切都应该工作,但所有的约束似乎添加它。我不知道它做了什么。

奇怪的是,做这样一个间接调用组装就好了:

void bar() { 
    return; 
} 

void foo() { 
    asm volatile (
     "ldi r30, lo8(%0)" "\n" 
     "ldi r31, hi8(%0)" "\n" 
     "icall" "\n" 
     : 
     : "p" (bar) 
    ); 
} 

汇编器生成这个样子的:

ldi r30, lo8(gs(_Z3barv)) 
ldi r31, hi8(gs(_Z3barv)) 
icall 

而且AVR-如不抱怨任何垃圾。

回答

1

请注意,call需要恒定的已知装配时间值。约束不包含该语义;它也将允许来自变量的指针(例如char* x),其中call不能处理。 (我似乎记得,有时gcc足够聪明,以这种方式进行优化,使得“p”在这里起作用 - 但这基本上是无证的行为和非确定性的,所以最好不要指望它。)

如果函数你打电话其实是编译时常量,你可以使用"i" (bar)。如果不是,那么你没有别的选择,只能使用icall,因为你已经知道了。

顺便说一句,AVR部分https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html#Machine-Constraints文件更多,AVR的具体约束。