[英]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是lr
, b 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.