0

我正在尝试通过与分支内联的 asm 调用 c 中的外部函数。我正在编译为 arm m0 指令集,但它返回错误的表达式。

代码是:

__asm volatile (
                "   cmp     r3,#0                   \n"                     
                "   b %[my_function]                \n" //Call function
                "   bx r14                          \n"
                : // no output
                : [my_function] "i" (my_function) // input
                : "r0" // clobber
            );

回报是:

/tmp/ccICkDIE.s: Assembler messages:
/tmp/ccICkDIE.s:152: Error: bad expression -- `b #my_function'

我们需要做什么?

4

2 回答 2

0

写完下面的内容后,我想起了ethernut 教程。他的答案几乎相同,

asm volatile(
    "mov lr, %1\n\t"
    "bx %0\n\t"
    : : "r" (main), "r" (JMPADDR));

OP 会很好地阅读本教程;即使它适用于传统的 ARM 而不是“m0”。


您可以使用'r'约束将地址放在寄存器中并跳转到它。

可以在在线编译器 Godbolt 上找到一个示例。

extern int my_function(void);

void f(void)
{
__asm volatile (
                "   cmp     r3,#0                   \n"                     
                "   b %[my_function]                \n" //Call function
                "   bx r14                          \n"
                : // no output
                : [my_function] "r" (my_function) // input
                : "r0" // clobber
            );

 }

随着输出,

f():
    ldr r3, .L2
       cmp     r3,#0                   
   b r3                
   bx r14                          

    bx  lr
.L2:
    .word   my_function()

我们可以看到输出的几个问题。r14lrb r3直接转移控制权并返回给 的调用者fcmp r3, #0似乎完全不需要(考虑到问题的有限背景)。

上面的示例回答了这个问题,它可以用于尾调用宏或其他用途,但它显然需要一些工作。像这样的函数指针,

int (*g)(void) = my_function;

也可以作为GCC 扩展汇编器的参数“my_function” 。

另一种方法是使用“C”宏字符串连接。这是一个起始样本,

#define xstr(s) str(s)
#define str(s) #s
#define TAIL_CALL(func) __asm volatile(" b  " str(func) "\n")

对于大多数代码大小(跳跃距离),分支将能够解析(4MB?)。如果使用函数指针方法,则没有问题。

于 2015-11-05T14:08:11.470 回答
0

你想要BL指示。这是“分支和链接”。它进行跳转并将返回地址存储在r14.

但是,你仍然有一个问题......当你这样做时BL,它会破坏需要的r14东西。即使在以下情况之后,您仍有更多工作要做:

stmfd   sp!,{v1-v6,lr}              // preserve caller registers
bl      %[my_function]              // call function
ldmfd   sp!,{v1-v6,pc} @std         // restore caller registers and return

你需要更多的调查。您可能想要反汇编编译的函数并查看您的内联汇编周围的包装器并相应地进行调整。它可能会stmfd/ldmfd为你做。尝试标记r14为 clobber。

仅使用BL. BX没有还原可能会产生无限循环或不可预测的结果。我会把它关掉

于 2015-11-04T23:22:45.303 回答