[英]Passing arguments from asm to C in on ARM
我在這個論壇上閱讀了很多主題,並在這個主題上找到了很多答案。 我實現了從我的匯編代碼向C函數傳遞5個參數。 為此,我使用了以下說明:
mov r0, #0
mov r1, #1
mov r2, #2
mov r3, #3
mov r4, #4
STR r4, [sp, #-4]!
BL displayRegistersValue
但是今天我試圖將整個寄存器傳遞給C函數以將它們保存在C結構中。 我嘗試了以下指令:
STMDB sp!, {registers that i want to save}
我的C函數:
displayRegistersValue(int registers[number_of_registers])
char printable = registers[0] + (int)'0'; // Convert in a printable character
print_uart0(&printable);
但我的表現並不好。 那么,如何訪問C代碼中的寄存器?
可以肯定的是,ARM標准僅允許R0-R3按值傳遞,因此最大值為4。 如果你需要更多的值,那么將它們推入堆棧並以這種方式訪問它們 - 就像編譯器那樣。 或者創建一個結構並傳遞其地址。
好吧,雙打了一下 ,我對了, 這是指向ARM調用約定的鏈接-向下一點。
要執行您想要的操作,請將某個內存位置(數組)的地址傳遞到匯編例程中。 一旦有了該地址(可能在r0內),就可以stmdb! 到該位置,您所有的寄存器值和該存儲器都將在C級別可見。
當心,這可能不會按照您的想法去做。 根據上面的調用約定鏈接,允許這些值進行相當大的更改。 如果這是用於調試,則最好使用調試器並以這種方式查看寄存器。
好的,你仍然不理解這里:
{
int registerValues[14];
myAsmRoutine(registerValues);
print_uart0(& registerValues);
}
myAsmRoutine:
stmia r0!, {r1-r14}
blx lr
我跳過了R0和PC,但您明白了。 此外,您需要做一些復雜的事情來將值更改為可打印的格式 - sprintf或itoa os之類的東西。
displayRegistersValue(int registers[number_of_registers])
這是一個數組,而不是結構,並作為指向某些對象(而不是一長串項目)的指針傳遞。 順便說一句,結構順便說一句。
通常最簡單的方法是構造一個C函數,該函數在asm中執行您想要的操作,然后查看編譯器生成的內容,然后從那里開始(使用ABI文檔進行確認,等等)。
#define NUMREGS 13
void displayRegistersValue(unsigned int registers[NUMREGS]);
void outer ( void )
{
unsigned int regs[NUMREGS];
displayRegistersValue(regs);
}
> arm-none-linux-gnueabi-gcc -O2 -c fun.c -o fun.o
> arm-none-linux-gnueabi-objdump -D fun.o
fun.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <outer>:
0: e52de004 push {lr} ; (str lr, [sp, #-4]!)
4: e24dd03c sub sp, sp, #60 ; 0x3c
8: e28d0004 add r0, sp, #4
c: ebfffffe bl 0 <displayRegistersValue>
10: e28dd03c add sp, sp, #60 ; 0x3c
14: e49df004 pop {pc} ; (ldr pc, [sp], #4)
您將需要執行類似的操作,通過添加到堆棧指針來在堆棧上騰出空間,保存lr,以便不將其與分支鏈接一起丟棄,將寄存器復制到該內存(堆棧)中,將r0指向起始地址。要傳遞的內存/數組,然后調用該函數(r0是要傳遞給該函數的第一個也是唯一的參數)。
push {lr}
mov lr,sp
stmdb sp!,{r0-r12}
mov r0,lr
bl displayRegistersValue
add sp,sp,#52
pop {lr}
數組作為指針傳遞到單個寄存器中。 如果要5個寄存器,則需要5個參數(int i1,int i2等)。
引用ARM APCS文檔:
“前四個寄存器r0-r3(a1-a4)用於將參數值傳遞給子程序並從函數返回結果值。它們也可用於在例程中保存中間值(但一般來說,只在子程序調用之間。)“
因此,如果要將超過4個值傳遞給C函數,則需要傳遞堆棧上的其余值。 更好的主意是將寄存器值放在已靜態分配的內存區域中,並將內存(指針)的地址傳遞給C函數。 函數可以取消引用指針以獲取寄存器值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.