是否可以使這個混合的C++/asm函數符合標準? 功能ePendSV()必須具有這樣的佈局:從裸露的asm函數訪問C++非POD類數據
ePendSV: //function entry point
mrs r0,PSP
stmdb r0!,{r4-r11,lr}
// compiler can generate any code here doing these things:
readyTcbQueue.pTcb.runTcb->psp = r0;
readyTcbQueue.pTcb.runTcb=readyTcbQueue.pTcb.readyTcb;
r0 = readyTcbQueue.pTcb.readyTcb->psp;
// work with r0 in assembly
ldmia r0!,{r4-r11,lr}
msr PSP,r0
bx lr
readyTcbQueue.pTcb是隻有兩個指針BragOsTcb對象一個簡單的結構對象;
struct{
BragOsTcb *runTcb;
BragOsTcb *readyTcb;
};
BragOsTcb非POD類,但如果沒有虛函數和虛擬繼承,看起來像這樣:
class BragOsTcb : public TcbCdllq, public TimerTcbCdllq, public BragOsObject{
public:
BragOsTcb();
....
private:
.....
public:
unsigned long psp;
....
};
TcbCdllq,TimerTcbCdllq,BragOsObject也簡單的類具有相似的佈局和無虛函數。但他們也是非POD。
我已經使這段代碼適用於gcc和clang,但它是一個非標準的黑客,可能無法正常工作。
__attribute__((naked)) void ePendSV(){
asm volatile("\
mrs r0,PSP \n\
stmdb r0!,{r4-r11,lr} \n\
\n\
ldr r1,=%0 \n\
ldmia r1,{r2,r3} // r2=runTcb, r3=readyTcb \n\
str r0,[r2,%1] // save psp \n\
str r3,[r1,#0] // runTcb=readyTcb \n\
ldr r0,[r3,%1] // readyTcb->psp \n\
\n\
// restore LR(EXC_RETURN),R11-R4 from new PSP, set new PSP, return \n\
ldmia r0!,{r4-r11,lr} \n\
msr PSP,r0 \n\
bx lr \n\
" :
: "i"(&readyTcbQueue.pTcb),"i"(&(((BragOsTcb*)0)->psp))
:);
// it'is an offsetof hack which might not work
}
謝謝!
這是很難有理由認爲PSP的ofsset將在運行時更改。你爲什麼擔心?它是一個圖書館,將用於你使用的不同cmpiler嗎? –
是的,這是一個庫,它可以在不同的編譯器上使用。 psp的偏移在運行時不會改變。但它可以從編譯器更改爲編譯器,或者可以被某些編譯器視爲錯誤。我用另外一個以上的asm關鍵字實現了這個功能。那個函數被clang-3.7拋棄了,並且出現了錯誤信息,但是在clang-3.5和gcc-4.8上工作。我可以做運行時檢查以確保psp的偏移量是正確的:if((long)(&readyTcbQueue.pTcb-> psp) \t \t!=((long)readyTcbQueue.pTcb +(long)(&(((BragOsTcb * )0) - > psp)))){ \t \t \t unrecoverableError(「....」); \t}' – brag
ePendSV是否會從您的圖書館外被調用?如果是這樣,它本身就是一個問題,因爲裸體屬性是編譯器特定的。但是,如果它是一個內部函數,那麼你可以添加一個簡短的asm子句,將你的地址加載到所需的寄存器中,然後調用函數 –