首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从裸asm函数访问C++非POD类数据

从裸asm函数访问C++非POD类数据
EN

Stack Overflow用户
提问于 2015-10-16 16:17:34
回答 1查看 209关注 0票数 0

是否可以使这个混合的c++/asm函数符合标准?函数ePendSV()必须具有以下布局:

代码语言:javascript
复制
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是一个简单的struct对象,只有两个指向BragOsTcb对象的指针;

代码语言:javascript
复制
struct{
    BragOsTcb *runTcb;
    BragOsTcb *readyTcb;
};

BragOsTcb是非POD类,但没有虚拟函数和虚拟继承,如下所示:

代码语言:javascript
复制
class BragOsTcb : public TcbCdllq, public TimerTcbCdllq, public BragOsObject{
public:
    BragOsTcb();
....
private:
.....
public:
    unsigned long psp;
....
};

TcbCdllq、TimerTcbCdllq、BragOsObject也是布局相似、没有虚拟化的简单类。但它们也是非POD的.

我做了这个代码,它工作在gcc和clang,但它是一个非标准的黑客,可能不起作用。

代码语言:javascript
复制
__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
}

谢谢!

EN

回答 1

Stack Overflow用户

发布于 2015-10-16 22:09:11

由于扩展的asm在裸功能上不支持gcc/clang

裸此属性允许编译器构造必要的函数声明,同时允许函数的主体为程序集代码。指定的函数将不具有编译器生成的序言/结语序列。只有基本的asm语句可以安全地包含在裸函数中(参见基本Asm)。虽然使用扩展的asm或基本的asm和C代码的混合物似乎可以工作,但它们不能依赖于可靠地工作,并且不受支持。https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#ARM-Function-Attributes

我们可以使用正常的C++函数,然后从裸的跳/调用它。

代码语言:javascript
复制
typedef unsigned long U32;

__attribute__((naked)) void ePendSV(){
    asm volatile("\
        mrs r0, PSP \n\
        stmdb r0!, {r4-r11,lr} \n\
        b realSwitchContext"); // this solution costs single jump instruction named **b**. It's valid for ARM-assembly in this case.
                              // Stack pointer has been saved in r0 register. we dont care about stack for now.
}

extern "C" void realSwitchContext(U32 psp){
    readyTcbQueue.pTcb.runTcb->psp = psp;
    BragOsTcb *tcb = readyTcbQueue.pTcb.readyTcb;
    readyTcbQueue.pTcb.runTcb = tcb;
    psp = tcb->psp;
    asm volatile("\
        ldmia %0!, {r4-r11,lr} \n\
        msr PSP, %0 \n\
        bx lr" : : "r"(psp)); // we just changed stack pointer then can return here and don't care about C++ stacked data
}

由于有两个堆栈指针- MSP和PSP,在上面的实现中有一些缺陷。如果bx lr将使用堆栈,MSP将被最后的C++指令破坏。下面的解决方案是正确的,但花费2‘昂贵’指令- bl (呼叫)和bx lr (返回)

代码语言:javascript
复制
__attribute__((naked)) void ePendSV(){
    asm volatile("\
        mrs r0, PSP \n\
        stmdb r0!, {r4-r11,lr} \n\
        bl realSwitchContext \n\
        ldmia r0!, {r4-r11,lr} \n\
        msr PSP, r0 \n\
        bx lr");
}

extern "C" U32 realSwitchContext(U32 psp){
    readyTcbQueue.pTcb.runTcb->psp = psp;
    BragOsTcb *tcb = readyTcbQueue.pTcb.readyTcb;
    readyTcbQueue.pTcb.runTcb = tcb;
    return tcb->psp;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33175120

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档