2014-11-14 112 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的具體約束。