簡體   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