2010-03-29 45 views
6

我從TriCore移植到ARM Cortex(Thumb-2指令集)的小型學術操作系統。爲了讓調度程序工作,我有時需要直接跳轉到另一個函數,而無需修改堆棧或鏈接寄存器。直接跳轉到另一個C++函數

在三核(或者說,上的TriCore-G ++),此包裝的模板(對於任何三個參數的函數)的工作原理:

template< class A1, class A2, class A3 > 
inline void __attribute__((always_inline)) 
JUMP3(void (*func)(A1, A2, A3), A1 a1, A2 a2, A3 a3) { 
    typedef void (* __attribute__((interrupt_handler)) Jump3)(A1, A2, A3); 
    ((Jump3)func)(a1, a2, a3); 
} 

//example for using the template: 
JUMP3(superDispatch, this, me, next); 

這將產生彙編指令J(又名JUMP)代替CALL,當跳轉到(否則正常的)C++函數superDispatch(SchedulerImplementation* obj, Task::Id from, Task::Id to)時,堆棧和CSA保持不變。

現在我需要上的ARM Cortex等效行爲(或者說,對於臂-NONE-Linux的gnueabi-G ++),即產生一個B(又名BRANCH)指令的,而不是BLX(又名BRANCH與鏈接和交換) 。但是arm-g ++沒有interrupt_handler屬性,我找不到任何等價的屬性。

於是,我就訴諸asm volatile並直接寫彙編代碼:

template< class A1, class A2, class A3 > 
inline void __attribute__((always_inline)) 
JUMP3(void (*func)(A1, A2, A3), A1 a1, A2 a2, A3 a3) { 
    asm volatile (
        "mov.w r0, %1;" 
        "mov.w r1, %2;" 
        "mov.w r2, %3;" 
        "b %0;" 
          : 
          : "r"(func), "r"(a1), "r"(a2), "r"(a3) 
          : "r0", "r1", "r2" 
       ); 
} 

到目前爲止,一切都很好,在我的理論,至少。在這種情況下,Thumb-2需要在寄存器中傳遞函數參數,即r0..r2,所以它應該可以工作。

但隨後的連接與

undefined reference to `r6' 

在asm語句的結束括號死了...我不知道這是怎麼回事。好吧,我不是C++的專家,asm語法不是很簡單......所以有人給我提示了嗎?爲arm-g ++提供正確的__attribute__將是一種方法,修正asm代碼的提示將是另一種方法。另一種方法可能是告訴編譯器,當輸入asm語句時,a1..a3應該已經在寄存器r0..r2中(我查看了一下,但沒有找到任何提示)。

+0

是a1,a2,a3指針嗎?嘗試將它們轉換爲'(void *)' – osgx 2010-03-29 16:33:27

+0

ARM中斷處理程序的屬性是'interrupt'。請參閱http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html – 2010-03-29 16:45:47

+0

@Mike:nope,該屬性仍會生成一個「BLX」指令... – orithena 2010-03-29 16:48:12

回答

0

嗯,我現在想通了哪裏出了問題。

由於TriCore每次調用另一個函數時都使用上下文保存區域(CSA)來保存整個CPU上下文,因此直接跳轉到另一個函數的整個概念在ARM Cortex上沒有實際意義。把它看作是第二個獨立的堆棧,每個堆棧隨着每個CALL而增長,並且隨着每個RET縮小。並且每個CSA塊具有恆定的大小。另一方面,ARM Cortex使用一個簡單的標準堆棧(好吧,它知道系統堆棧和線程堆棧,但在這裏並不重要) - 而GCC只是保存每個函數所需的東西,所以每個框架都有不同的大小。簡單地跳到另一個函數是不可能的,因爲一旦跳轉功能開始保存它使用的非易失性寄存器,堆棧就會被破壞。

關於r6的未定義引用的鏈接器錯誤...我應該更仔細地閱讀指令集文檔。 B是無條件轉移到立即地址,BX是期望分支地址寄存器中的指令。我被手冊中的指令列表所迷惑,其中BX簡稱爲「分支交換」。我不想交換任何東西,我想要一個簡單的跳躍,所以我沒有進一步閱讀。

所以,在BBX交換asm volatile代碼後,編譯了代碼。但是,如上所述,整個概念無法按預期工作。也許別人可以找到該代碼的用例,我不得不求助於經典函數調用...

1

鏈接錯誤是由嘗試使用分支指令跳轉到指針引起的。這會生成類似b r6的代碼,因爲r6不是符號,所以無法鏈接。將分支指令更改爲mov pc,%0,並且您應該得到正確的跳轉。

正如我在評論中提到的,ARM中斷處理程序聲明爲interrupt屬性,但是您發現這不影響它們的調用方式。我想這是一個特定於平臺的技巧,恰巧在TriCore上做正確的事情。

您可以嘗試使用GCC的擴展語法register int reg0 asm("r0") = a1;而不是易失性mov指令在特定寄存器中聲明變量。這可能會讓編譯器生成更好的代碼。