Sam*_*all 5 c c++ embedded clang inline-assembly
我正在使用一个专有的MCU,它有一个内置的金属库(掩模ROM).我正在使用的编译器是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
}
Run Code Online (Sandbox Code Playgroud)
现在这有一个明显的问题,即当变量"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");
}
Run Code Online (Sandbox Code Playgroud)
这对我来说真的很难看,而且应该有更好的方法.另外我担心编译器可能会在两者之间做一些废话,因为调用本身并没有表明它需要asmHex变量.不幸的是,((volatile void(*)(int))(MASKROM_EchoByte))(asmHex)不起作用,因为它将遵循C-convention,它将参数放入R2 +(R1保留用于刮擦)
请注意,遗憾的是,更改Mask ROM库是不可能的,并且有太多常用的例程在C/C++中重新创建它们.
干杯,谢谢.
编辑:我应该注意,虽然我可以调用ASM块中的函数,但编译器对无调用函数进行了优化,并且通过调用汇编看起来没有调用.如果有某种方式指示内联ASM包含函数调用,我可以使用此路由,但否则返回地址可能会被破坏.在任何情况下我都无法找到办法.
根据上面的评论:
最传统的答案是,您应该在程序集中(在文件中.s
)实现一个存根函数,它只是为您执行古怪的调用。在 ARM 中,这看起来像
// void EchoByte(int hex);
_EchoByte:
push {lr}
mov r1, r0 // move our first parameter into r1
bl _MASKROM_EchoByte
pop pc
Run Code Online (Sandbox Code Playgroud)
每个掩码 ROM 例程实现这些存根之一,就完成了。
那是什么?您有 500 个掩码 ROM 例程并且不想剪切和粘贴这么多代码?然后添加一个间接级别:
// typedef void MASKROM_Routine(int r1, ...);
// void GeneralPurposeStub(MASKROM_Routine *f, int arg, ...);
_GeneralPurposeStub:
bx r0
Run Code Online (Sandbox Code Playgroud)
使用语法调用此存根GeneralPurposeStub(&MASKROM_EchoByte, hex)
。它适用于任何需要r1
. 任何真正古怪的入口点仍然需要自己的手工编码的程序集存根。
但是,如果您真的、真的、真的必须通过 C 函数中的内联汇编来完成此操作,那么(正如 @JasonD 指出的那样)您需要做的就是将链接寄存器添加lr
到 clobber 列表中。
void EchoByte(int hex)
{
register int r1 asm("r1") = hex;
asm volatile(
"bl _MASKROM_EchoByte"
:
: "r"(r1)
: "r1", "lr" // Compare the codegen with and without this "lr"!
);
}
Run Code Online (Sandbox Code Playgroud)