繁体   English   中英

ASM内联调用C外部功能

[英]ASM Inline call C external function

我正在尝试通过与分支内联的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'

我们需要做什么?

您需要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标记为破坏者。

仅使用BL可能会更好。 没有还原的BX可能会产生无限循环或不可预测的结果。 我会离开它

组成下面的内容之后,我想起了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()

我们可以看到输出有几个问题。 r14是lrb r3将直接转移控制权并返回给f的调用者。 似乎完全不需要cmp 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?)。 如果使用函数指针方法,则没有问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM