内联ASM的非传统呼叫

时间:2013-01-03 20:01:38

标签: c++ c embedded clang inline-assembly

我正在使用具有金属内置库(掩模ROM)的专有MCU。我正在使用的编译器是clang,它使用类似GCC的内联ASM。我遇到的问题是调用库,因为库没有一致的调用约定。虽然我找到了一个解决方案,但我发现在某些情况下编译器会在调用之前立即对clobber进行优化,我认为我的工作方式有问题。这是我正在使用的代码:

int EchoByte()
{
    register int asmHex __asm__ ("R1") = Hex;
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
    ((volatile void (*)(void))(MASKROM_EchoByte))(); //MASKROM_EchoByte is a 16-bit integer with the memory location of the function
}

现在这有一个明显的问题,即当变量“asmHex”被声明为寄存器R1时,实际调用不使用它,因此编译器“不知道”在调用时保留R1。我使用以下代码来消除这种情况:

int EchoByte()
{
    register int asmHex __asm__ ("R1") = Hex;
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
    ((volatile void (*)(void))(MASKROM_EchoByte))();
    asm volatile("//Assert Input to R1 for MASKROM_EchoByte"
            :
            :"r"(asmHex)
            :"%R1");
}

这对我来说真的很难看,而且应该有更好的方法。另外我担心编译器可能会在两者之间做一些废话,因为调用本身并没有表明它需要asmHex变量。不幸的是,((volatile void(*)(int))(MASKROM_EchoByte))(asmHex)不起作用,因为它将遵循C-convention,它将参数放入R2 +(R1保留用于刮擦)

请注意,遗憾的是更改Mask ROM库是不可能的,并且有太多常用的例程在C / C ++中重新创建它们。

干杯,谢谢。

编辑:我应该注意,虽然我可以在ASM块中调用该函数,但编译器对无调用函数进行了优化,并且通过调用汇编看起来没有调用。如果有某种方式指示内联ASM包含函数调用,我可以使用此路由,但否则返回地址可能会被破坏。在任何情况下,我都无法找到办法。

1 个答案:

答案 0 :(得分:1)

根据上述评论:

最常见的答案是你应该在程序集中(在.s文件中)实现一个简单函数,它只是为你执行古怪的调用。在ARM中,这看起来像

// void EchoByte(int hex);

_EchoByte:
    push {lr}
    mov  r1, r0       // move our first parameter into r1
    bl   _MASKROM_EchoByte
    pop  pc

每个mask-ROM例程实现其中一个存根,你就完成了。

那是什么?你有500个掩模ROM例程,不想剪切和粘贴这么多代码?然后添加一个间接级别:

// typedef void MASKROM_Routine(int r1, ...);
// void GeneralPurposeStub(MASKROM_Routine *f, int arg, ...);

_GeneralPurposeStub:
    bx   r0

使用语法GeneralPurposeStub(&MASKROM_EchoByte, hex)调用此存根。它适用于需要r1中的参数的任何掩码ROM入口点。任何真正古怪的入口点仍然需要他们自己的手工编码的汇编存根。

但是,如果你真的,真的,真的必须通过C函数中的内联汇编来实现,然后(如@JasonD指出的那样)你需要做的就是添加链接寄存器{{1到了clobber列表。

lr