我正在使用具有内置金属库(掩模 ROM)的专有 MCU。我使用的编译器是 clang,它使用类似 GCC 的内联 ASM。我遇到的问题是调用库,因为库没有一致的调用约定。虽然我找到了解决方案,但我发现在某些情况下,编译器会在调用前立即进行破坏注册的优化,我认为我做事的方式有问题。这是我正在使用的代码:
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 约定,它将参数放入 R2+(R1 保留用于抓取)
请注意,不幸的是,更改 Mask ROM 库是不可能的,而且有太多常用例程无法在 C/C++ 中全部重新创建。
干杯,谢谢。
编辑:我应该注意,虽然我可以调用 ASM block 中的函数,但编译器对无调用函数进行了优化,并且通过在汇编中调用它看起来没有调用。如果有某种方法表明内联 ASM 包含函数调用,我可以走这条路,否则返回地址可能会被破坏。无论如何,我都无法找到执行此操作的方法。
最佳答案
根据上面的评论:
最传统的答案是您应该在程序集中(在 .s
文件中)实现一个 stub 函数,它只为您执行古怪的调用。在 ARM 中,这看起来像
// void EchoByte(int hex);
_EchoByte:
push {lr}
mov r1, r0 // move our first parameter into r1
bl _MASKROM_EchoByte
pop pc
每个掩码 ROM 例程实现这些 stub 之一,您就完成了。
那是什么?您有 500 个掩码 ROM 例程,不想剪切和粘贴那么多代码?然后添加一个间接级别:
// typedef void MASKROM_Routine(int r1, ...);
// void GeneralPurposeStub(MASKROM_Routine *f, int arg, ...);
_GeneralPurposeStub:
bx r0
使用语法 GeneralPurposeStub(&MASKROM_EchoByte, hex)
调用这个 stub 。它适用于任何需要 r1
中的参数的 mask-ROM 入口点。任何真的古怪的入口点仍然需要它们自己的手工编码的程序集 stub 。
但是如果你真的,真的,真的必须通过 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"!
);
}
关于c++ - 使用内联 ASM 进行非常规调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14146303/