简体   繁体   English

ASM内联调用C外部功能

[英]ASM Inline call C external function

I'm trying to call an external function in c by an asm inline with a branch. 我正在尝试通过与分支内联的asm在c中调用外部函数。 I'm compiling to an arm m0 instruction set but it returns bad expression. 我正在编译为arm m0指令集,但它返回错误的表达式。

The code is: 代码是:

__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
            );

The return is: 返回是:

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

What we need to do? 我们需要做什么?

You want the BL instruction. 您需要BL指令。 This is "branch and link". 这是“分支和链接”。 It does a jump and stores the return address in r14 . 它进行跳转并将返回地址存储在r14

But, you've still got a problem ... When you do BL , it destroys the r14 that you need. 但是,你仍然有一个问题...当你做BL ,它破坏r14所需要的。 You've still got more work to do, even after the following: 即使执行以下操作,您仍然需要做更多的工作:

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

You'll need more investigation. 您需要更多调查。 You might want to disassemble the compiled function and see what wrapper goes around your inline asm and adjust accordingly. 您可能需要反汇编已编译的函数,并查看内联组件周围的包装器并进行相应的调整。 It may do the stmfd/ldmfd for you. 它可能会为您做stmfd/ldmfd Try marking r14 as a clobber. 尝试将r14标记为破坏者。

You may be better off with just the BL . 仅使用BL可能会更好。 The BX without restore might produce an infinite loop or unpredictable results. 没有还原的BX可能会产生无限循环或不可预测的结果。 I'd leave it off 我会离开它

After composing the below, I remembered the ethernut tutorial . 组成下面的内容之后,我想起了ethernut教程 He has virtually the same answer, 他几乎有相同的答案,

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

The OP would do well to read this tutorial; OP最好阅读本教程。 even though it is for traditional ARM as opposed to an 'm0'. 即使是传统ARM而不是'm0'。


You may use the 'r' constraint to place the address in a register and branch to it. 您可以使用'r'约束将地址放置在寄存器中并跳转到它。

An example can be found on the online compiler godbolt. 可以在在线编译器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
            );

 }

With the output, 随着输出,

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

    bx  lr
.L2:
    .word   my_function()

We can see several issues with the output. 我们可以看到输出有几个问题。 r14 is lr and the b r3 will transfer control directly and return to the caller of f . r14是lrb r3将直接转移控制权并返回给f的调用者。 The cmp r3, #0 seems completely un-needed (given limited context of question). 似乎完全不需要cmp r3, #0 (因为问题的上下文有限)。

The sample above answers the question and it could be used for a tail-call macro or other use, but it obviously needs some work. 上面的示例回答了这个问题,它可以用于尾部调用宏或其他用途,但是显然需要一些工作。 A function pointer like, 一个函数指针,例如

int (*g)(void) = my_function;

will also work as the parameter 'my_function' to the GCC extended assembler. 还将用作GCC扩展汇编程序的参数“ my_function”

Another method is just to use 'C' macro string concatenation. 另一种方法是仅使用“ C”宏字符串连接。 Here is a starting sample, 这是一个初始示例,

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

For most code sizes (jump distance), the branch will be able to resolve (4MB?). 对于大多数代码大小(跳转距离),分支将能够解析(4MB?)。 If you use the function pointer method, then there is no issue. 如果使用函数指针方法,则没有问题。

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

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