是否可以使这个混合的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子句,将你的地址加载到所需的寄存器中,然后调用函数 –